/*
Copyright 2024 New Vector Ltd.
Copyright 2017 Vector Creations Ltd
Copyright 2016 OpenMarket Ltd

SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
 */

#import "RoomSettingsViewController.h"

#import "TableViewCellWithLabelAndLargeTextView.h"
#import "TableViewCellWithCheckBoxAndLabel.h"

#import "SegmentedViewController.h"

#import "AvatarGenerator.h"
#import "Tools.h"

#import "MXRoom+Riot.h"
#import "MXRoomSummary+Riot.h"

#import "GeneratedInterface-Swift.h"

#import "RoomMemberDetailsViewController.h"

#import <MobileCoreServices/MobileCoreServices.h>

enum
{
    SECTION_TAG_MAIN,
    SECTION_TAG_ACCESS,
    SECTION_TAG_PROMOTION,
    SECTION_TAG_HISTORY,
    SECTION_TAG_ADDRESSES,
    SECTION_TAG_BANNED_USERS,
    SECTION_TAG_BANNED_ADVANCED
};

enum
{
    ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO,
    ROOM_SETTINGS_MAIN_SECTION_ROW_NAME,
    ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC,
    ROOM_SETTINGS_MAIN_SECTION_ROW_TAG,
    ROOM_SETTINGS_MAIN_SECTION_ROW_DIRECT_CHAT,
    ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS
};

enum
{
    ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ACCESS,
    ROOM_SETTINGS_ROOM_ACCESS_DIRECTORY_VISIBILITY,
    ROOM_SETTINGS_ROOM_ACCESS_MISSING_ADDRESS_WARNING
};

enum
{
    ROOM_SETTINGS_ROOM_PROMOTE_SECTION_ROW_SUGGEST
};

enum
{
    ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_ANYONE,
    ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY,
    ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_INVITED,
    ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_JOINED
};

enum
{
    ROOM_SETTINGS_ADVANCED_ROOM_ID,
    ROOM_SETTINGS_ADVANCED_ENCRYPT_TO_VERIFIED,
    ROOM_SETTINGS_ADVANCED_ENCRYPTION_ENABLED,
    ROOM_SETTINGS_ADVANCED_ENABLE_ENCRYPTION,
    ROOM_SETTINGS_ADVANCED_ENCRYPTION_DISABLED
};

enum
{
    ROOM_SETTINGS_ROOM_ADDRESS_NEW_ALIAS,
    ROOM_SETTINGS_ROOM_ADDRESS_NO_LOCAL_ADDRESS,
    ROOM_SETTINGS_ROOM_ADDRESS_ALIAS_OFFSET = 1000
};

#define ROOM_TOPIC_CELL_HEIGHT 124

NSString *const kRoomSettingsAvatarKey = @"kRoomSettingsAvatarKey";
NSString *const kRoomSettingsAvatarURLKey = @"kRoomSettingsAvatarURLKey";
NSString *const kRoomSettingsNameKey = @"kRoomSettingsNameKey";
NSString *const kRoomSettingsTopicKey = @"kRoomSettingsTopicKey";
NSString *const kRoomSettingsTagKey = @"kRoomSettingsTagKey";
NSString *const kRoomSettingsMuteNotifKey = @"kRoomSettingsMuteNotifKey";
NSString *const kRoomSettingsDirectChatKey = @"kRoomSettingsDirectChatKey";
NSString *const kRoomSettingsJoinRuleKey = @"kRoomSettingsJoinRuleKey";
NSString *const kRoomSettingsGuestAccessKey = @"kRoomSettingsGuestAccessKey";
NSString *const kRoomSettingsDirectoryKey = @"kRoomSettingsDirectoryKey";
NSString *const kRoomSettingsHistoryVisibilityKey = @"kRoomSettingsHistoryVisibilityKey";
NSString *const kRoomSettingsNewAliasesKey = @"kRoomSettingsNewAliasesKey";
NSString *const kRoomSettingsRemovedAliasesKey = @"kRoomSettingsRemovedAliasesKey";
NSString *const kRoomSettingsCanonicalAliasKey = @"kRoomSettingsCanonicalAliasKey";
NSString *const kRoomSettingsEncryptionKey = @"kRoomSettingsEncryptionKey";
NSString *const kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey = @"kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey";

NSString *const kRoomSettingsNameCellViewIdentifier = @"kRoomSettingsNameCellViewIdentifier";
NSString *const kRoomSettingsTopicCellViewIdentifier = @"kRoomSettingsTopicCellViewIdentifier";
NSString *const kRoomSettingsWarningCellViewIdentifier = @"kRoomSettingsWarningCellViewIdentifier";
NSString *const kRoomSettingsNewAddressCellViewIdentifier = @"kRoomSettingsNewAddressCellViewIdentifier";
NSString *const kRoomSettingsAddressCellViewIdentifier = @"kRoomSettingsAddressCellViewIdentifier";
NSString *const kRoomSettingsAdvancedCellViewIdentifier = @"kRoomSettingsAdvancedCellViewIdentifier";
NSString *const kRoomSettingsAdvancedEnableE2eCellViewIdentifier = @"kRoomSettingsAdvancedEnableE2eCellViewIdentifier";
NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSettingsAdvancedE2eEnabledCellViewIdentifier";

@interface RoomSettingsViewController () <SingleImagePickerPresenterDelegate, TableViewSectionsDelegate, RoomAccessCoordinatorBridgePresenterDelegate, RoomSuggestionCoordinatorBridgePresenterDelegate>
{
    // The updated user data
    NSMutableDictionary<NSString*, id> *updatedItemsDict;
    
    // The current table items
    UITextField* nameTextField;
    UITextView* topicTextView;
    
    // The room tag items
    TableViewCellWithCheckBoxes *roomTagCell;
    
    // Room Access items
    
    UISwitch *directoryVisibilitySwitch;
    MXRoomDirectoryVisibility actualDirectoryVisibility;
    MXHTTPOperation* actualDirectoryVisibilityRequest;
    
    // History Visibility items
    NSMutableDictionary<MXRoomHistoryVisibility, TableViewCellWithCheckBoxAndLabel*> *historyVisibilityTickCells;
    
    // Room aliases
    NSMutableArray<NSString *> *roomAddresses;
    NSUInteger localAddressesCount;
    UITextField* addAddressTextField;
    
    // The potential image loader
    MXMediaLoader *uploader;
    
    // The pending http operation
    MXHTTPOperation* pendingOperation;
    
    UIAlertController *currentAlert;
    
    // listen to more events than the mother class
    id extraEventsListener;
    
    // Observe kAppDelegateDidTapStatusBarNotification to handle tap on clock status bar.
    id appDelegateDidTapStatusBarNotificationObserver;
    
    // A copy of the banned members
    NSArray<MXRoomMember*> *bannedMembers;
    
    // Observe kThemeServiceDidChangeThemeNotification to handle user interface theme change.
    id kThemeServiceDidChangeThemeNotificationObserver;
    
    RoomAccessCoordinatorBridgePresenter *roomAccessPresenter;
    
    RoomSuggestionCoordinatorBridgePresenter *roomSuggestionPresenter;
}

@property (nonatomic, strong) SingleImagePickerPresenter *imagePickerPresenter;

@property (nonatomic, strong) TableViewSections *tableViewSections;

@end

@implementation RoomSettingsViewController

- (void)finalizeInit
{
    [super finalizeInit];
    
    _selectedRoomSettingsField = RoomSettingsViewControllerFieldNone;
    
    // Setup `MXKViewControllerHandling` properties
    self.enableBarTintColorStatusChange = NO;
    self.rageShakeManager = [RageShakeManager sharedManager];
}

- (void)initWithSession:(MXSession *)session andRoomId:(NSString *)roomId
{
    [super initWithSession:session andRoomId:roomId];
    
    // Add an additional listener to update banned users
    self->extraEventsListener = [mxRoom listenToEventsOfTypes:@[kMXEventTypeStringRoomMember] onEvent:^(MXEvent *event, MXTimelineDirection direction, MXRoomState *roomState) {

        if (direction == MXTimelineDirectionForwards)
        {
            [self updateRoomState:roomState];
        }
    }];
}

- (void)updateRoomState:(MXRoomState *)newRoomState
{
    [super updateRoomState:newRoomState];
    
    bannedMembers = [mxRoomState.members membersWithMembership:MXMembershipBan];
}

- (UINavigationItem*)getNavigationItem
{
    // Check whether the view controller is currently displayed inside a segmented view controller or not.
    UIViewController* topViewController = ((self.parentViewController) ? self.parentViewController : self);
    
    return topViewController.navigationItem;
}

- (void)setNavBarButtons
{
    [self getNavigationItem].rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(onSave:)];
    [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
    [self getNavigationItem].leftBarButtonItem  = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(onCancel:)];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    updatedItemsDict = [[NSMutableDictionary alloc] init];
    historyVisibilityTickCells = [[NSMutableDictionary alloc] initWithCapacity:4];
    
    roomAddresses = [NSMutableArray array];
    
    [self.tableView registerClass:MXKTableViewCellWithLabelAndSwitch.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier]];
    [self.tableView registerClass:MXKTableViewCellWithLabelAndMXKImageView.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndMXKImageView defaultReuseIdentifier]];
    
    // Use a specific cell identifier for the room name, the topic and the address in order to be able to keep reference
    // on the text input field without being disturbed by the cell dequeuing process.
    [self.tableView registerClass:MXKTableViewCellWithLabelAndTextField.class forCellReuseIdentifier:kRoomSettingsNameCellViewIdentifier];
    [self.tableView registerClass:TableViewCellWithLabelAndLargeTextView.class forCellReuseIdentifier:kRoomSettingsTopicCellViewIdentifier];
    [self.tableView registerClass:MXKTableViewCellWithLabelAndTextField.class forCellReuseIdentifier:kRoomSettingsNewAddressCellViewIdentifier];
    [self.tableView registerClass:UITableViewCell.class forCellReuseIdentifier:kRoomSettingsAddressCellViewIdentifier];
    [self.tableView registerClass:UITableViewCell.class forCellReuseIdentifier:kRoomSettingsWarningCellViewIdentifier];
    
    [self.tableView registerClass:MXKTableViewCellWithButton.class forCellReuseIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]];
    [self.tableView registerClass:TableViewCellWithCheckBoxes.class forCellReuseIdentifier:[TableViewCellWithCheckBoxes defaultReuseIdentifier]];
    [self.tableView registerClass:TableViewCellWithCheckBoxAndLabel.class forCellReuseIdentifier:[TableViewCellWithCheckBoxAndLabel defaultReuseIdentifier]];
    [self.tableView registerClass:MXKTableViewCell.class forCellReuseIdentifier:[MXKTableViewCell defaultReuseIdentifier]];
    [self.tableView registerClass:TitleAndRightDetailTableViewCell.class forCellReuseIdentifier:[TitleAndRightDetailTableViewCell defaultReuseIdentifier]];
    
    // Enable self sizing cells
    self.tableView.rowHeight = UITableViewAutomaticDimension;
    self.tableView.estimatedRowHeight = 44;
    
    [self setNavBarButtons];
    
    // Observe user interface theme change.
    kThemeServiceDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kThemeServiceDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
        
        [self userInterfaceThemeDidChange];
        
    }];
    [self userInterfaceThemeDidChange];
    
    _tableViewSections = [TableViewSections new];
    _tableViewSections.delegate = self;
    [self updateSections];
}

- (void)userInterfaceThemeDidChange
{
    [ThemeService.shared.theme applyStyleOnNavigationBar:self.navigationController.navigationBar];

    self.activityIndicator.backgroundColor = ThemeService.shared.theme.overlayBackgroundColor;
    
    // Check the table view style to select its bg color.
    self.tableView.backgroundColor = ((self.tableView.style == UITableViewStylePlain) ? ThemeService.shared.theme.backgroundColor : ThemeService.shared.theme.headerBackgroundColor);
    self.view.backgroundColor = self.tableView.backgroundColor;
    self.tableView.separatorColor = ThemeService.shared.theme.lineBreakColor;
    
    if (self.tableView.dataSource)
    {
        [self.tableView reloadData];
    }

    [self setNeedsStatusBarAppearanceUpdate];
}

- (UIStatusBarStyle)preferredStatusBarStyle
{
    return ThemeService.shared.theme.statusBarStyle;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    [self.screenTracker trackScreen];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didUpdateRules:) name:kMXNotificationCenterDidUpdateRules object:nil];
    
    // Observe appDelegateDidTapStatusBarNotificationObserver.
    appDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
        
        [self.tableView setContentOffset:CGPointMake(-self.tableView.adjustedContentInset.left, -self.tableView.adjustedContentInset.top) animated:YES];
        
    }];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    
    // Edit the selected field if any
    if (_selectedRoomSettingsField != RoomSettingsViewControllerFieldNone)
    {
        self.selectedRoomSettingsField = _selectedRoomSettingsField;
    }
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    
    [self dismissFirstResponder];
    
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kMXNotificationCenterDidUpdateRules object:nil];
    
    if (appDelegateDidTapStatusBarNotificationObserver)
    {
        [[NSNotificationCenter defaultCenter] removeObserver:appDelegateDidTapStatusBarNotificationObserver];
        appDelegateDidTapStatusBarNotificationObserver = nil;
    }
}

// Those methods are called when the viewcontroller is added or removed from a container view controller.
- (void)willMoveToParentViewController:(nullable UIViewController *)parent
{
    // Check whether the view is removed from its parent.
    if (!parent)
    {
        [self dismissFirstResponder];
        
        // Prompt user to save changes (if any).
        if (updatedItemsDict.count)
        {
            [self promptUserToSaveChanges];
        }
    }
    
    [super willMoveToParentViewController:parent];
}
- (void)didMoveToParentViewController:(nullable UIViewController *)parent
{
    [super didMoveToParentViewController:parent];
    
    [self setNavBarButtons];
}

- (void)destroy
{
    self.navigationItem.rightBarButtonItem.enabled = NO;
    
    if (currentAlert)
    {
        [currentAlert dismissViewControllerAnimated:NO completion:nil];
        currentAlert = nil;
    }
    
    if (uploader)
    {
        [uploader cancel];
        uploader = nil;
    }
    
    if (pendingOperation)
    {
        [pendingOperation cancel];
        pendingOperation = nil;
    }
    
    if (actualDirectoryVisibilityRequest)
    {
        [actualDirectoryVisibilityRequest cancel];
        actualDirectoryVisibilityRequest = nil;
    }
    
    if (kThemeServiceDidChangeThemeNotificationObserver)
    {
        [[NSNotificationCenter defaultCenter] removeObserver:kThemeServiceDidChangeThemeNotificationObserver];
        kThemeServiceDidChangeThemeNotificationObserver = nil;
    }
    
    if (appDelegateDidTapStatusBarNotificationObserver)
    {
        [[NSNotificationCenter defaultCenter] removeObserver:appDelegateDidTapStatusBarNotificationObserver];
        appDelegateDidTapStatusBarNotificationObserver = nil;
    }
    
    updatedItemsDict = nil;
    historyVisibilityTickCells = nil;
    
    roomAddresses = nil;
    
    if (extraEventsListener)
    {
        MXWeakify(self);
        [mxRoom liveTimeline:^(id<MXEventTimeline> liveTimeline) {
            MXStrongifyAndReturnIfNil(self);

            [liveTimeline removeListener:self->extraEventsListener];
            self->extraEventsListener = nil;
        }];
    }
    
    [super destroy];
}

- (void)withdrawViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion
{
    // Check whether the current view controller is displayed inside a segmented view controller in order to withdraw the right item
    if (self.parentViewController && [self.parentViewController isKindOfClass:SegmentedViewController.class])
    {
        [((SegmentedViewController*)self.parentViewController) withdrawViewControllerAnimated:animated completion:completion];
    }
    else
    {
        [super withdrawViewControllerAnimated:animated completion:completion];
    }
}

- (void)refreshRoomSettings
{
    [self retrieveActualDirectoryVisibility];
    
    // Check whether a text input is currently edited
    BOOL isNameEdited = nameTextField ? nameTextField.isFirstResponder : NO;
    BOOL isTopicEdited = topicTextView ? topicTextView.isFirstResponder : NO;
    BOOL isAddressEdited = addAddressTextField ? addAddressTextField.isFirstResponder : NO;
    
    // Trigger a full table reloadData
    [self updateSections];
    
    // Restore the previous edited field
    if (isNameEdited)
    {
        [self editRoomName];
    }
    else if (isTopicEdited)
    {
        [self editRoomTopic];
    }
    else if (isAddressEdited)
    {
        [self editAddRoomAddress];
    }
}

- (void)updateSections
{
    //  update local data
    // Refresh here the room addresses list.
    [roomAddresses removeAllObjects];
    localAddressesCount = 0;
    
    NSArray *removedAliases = updatedItemsDict[kRoomSettingsRemovedAliasesKey];
    
    NSArray *aliases = mxRoomState.aliases;
    if (aliases)
    {
        for (NSString *alias in aliases)
        {
            // Check whether the user did not remove it
            if (!removedAliases || [removedAliases indexOfObject:alias] == NSNotFound)
            {
                // Add it
                if ([alias hasSuffix:self.mainSession.matrixRestClient.homeserverSuffix])
                {
                    [roomAddresses insertObject:alias atIndex:localAddressesCount];
                    localAddressesCount++;
                }
                else
                {
                    [roomAddresses addObject:alias];
                }
            }
        }
    }
    
    aliases = updatedItemsDict[kRoomSettingsNewAliasesKey];
    for (NSString *alias in aliases)
    {
        // Add this new alias to local addresses
        [roomAddresses insertObject:alias atIndex:localAddressesCount];
        localAddressesCount++;
    }
    
    //  create sections
    NSMutableArray<Section*> *tmpSections = [NSMutableArray arrayWithCapacity:SECTION_TAG_BANNED_ADVANCED + 1];
    
    Section *sectionMain = [Section sectionWithTag:SECTION_TAG_MAIN];
    [sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO];
    [sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_NAME];
    [sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC];
    [sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_TAG];
    if (RiotSettings.shared.roomSettingsScreenShowDirectChatOption)
    {
        [sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_DIRECT_CHAT];
    }
    if (!BuildSettings.showNotificationsV2)
    {
        [sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS];
    }
    [tmpSections addObject:sectionMain];
    
    if (RiotSettings.shared.roomSettingsScreenAllowChangingAccessSettings)
    {
        Section *sectionAccess = [Section sectionWithTag:SECTION_TAG_ACCESS];
        [sectionAccess addRowWithTag:ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ACCESS];
        
        // Check whether a room address is required for the current join rule
        NSString *joinRule = updatedItemsDict[kRoomSettingsJoinRuleKey];
        if (!joinRule)
        {
            // Use the actual values if no change is pending.
            joinRule = mxRoomState.joinRule;
        }
        
        if ([joinRule isEqualToString:kMXRoomJoinRulePublic] && !roomAddresses.count)
        {
            // Notify the user that a room address is required.
            [sectionAccess addRowWithTag:ROOM_SETTINGS_ROOM_ACCESS_MISSING_ADDRESS_WARNING];
        }
        
        if (mxRoom.isDirect)
        {
            sectionAccess.headerTitle = [VectorL10n roomDetailsAccessSectionForDm];
        }
        else
        {
            sectionAccess.headerTitle = [VectorL10n roomDetailsAccessSection];
        }
        [tmpSections addObject:sectionAccess];
        
        if (RiotSettings.shared.roomSettingsScreenAllowChangingAccessSettings)
        {
            Section *promotionAccess = [Section sectionWithTag:SECTION_TAG_PROMOTION];
            promotionAccess.headerTitle = VectorL10n.roomDetailsPromoteRoomTitle;
            [promotionAccess addRowWithTag:ROOM_SETTINGS_ROOM_ACCESS_DIRECTORY_VISIBILITY];
            [promotionAccess addRowWithTag:ROOM_SETTINGS_ROOM_PROMOTE_SECTION_ROW_SUGGEST];
            [tmpSections addObject:promotionAccess];
        }
    }
    
    if (RiotSettings.shared.roomSettingsScreenAllowChangingHistorySettings)
    {
        Section *sectionHistory = [Section sectionWithTag:SECTION_TAG_HISTORY];
        [sectionHistory addRowWithTag:ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_ANYONE];
        [sectionHistory addRowWithTag:ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY];
        [sectionHistory addRowWithTag:ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_INVITED];
        [sectionHistory addRowWithTag:ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_JOINED];
        sectionHistory.headerTitle = [VectorL10n roomDetailsHistorySection];
        [tmpSections addObject:sectionHistory];
    }
    
    if (RiotSettings.shared.roomSettingsScreenShowAddressSettings)
    {
        Section *sectionAddresses = [Section sectionWithTag:SECTION_TAG_ADDRESSES];
        if (localAddressesCount)
        {
            for (NSInteger counter = 0; counter < roomAddresses.count; counter++)
            {
                [sectionAddresses addRowWithTag:ROOM_SETTINGS_ROOM_ADDRESS_ALIAS_OFFSET + counter];
            }
        }
        else
        {
            [sectionAddresses addRowWithTag:ROOM_SETTINGS_ROOM_ADDRESS_NO_LOCAL_ADDRESS];
        }
        [sectionAddresses addRowWithTag:ROOM_SETTINGS_ROOM_ADDRESS_NEW_ALIAS];
        sectionAddresses.headerTitle = [VectorL10n roomDetailsAddressesSection];
        [tmpSections addObject:sectionAddresses];
    }
    
    if (bannedMembers.count)
    {
        Section *sectionBannedUsers = [Section sectionWithTag:SECTION_TAG_BANNED_USERS];
        
        for (NSInteger counter = 0; counter < bannedMembers.count; counter++)
        {
            [sectionBannedUsers addRowWithTag:counter];
        }
        
        sectionBannedUsers.headerTitle = [VectorL10n roomDetailsBannedUsersSection];
        [tmpSections addObject:sectionBannedUsers];
    }
    
    if (RiotSettings.shared.roomSettingsScreenShowAdvancedSettings)
    {
        Section *sectionAdvanced = [Section sectionWithTag:SECTION_TAG_BANNED_ADVANCED];
        
        [sectionAdvanced addRowWithTag:ROOM_SETTINGS_ADVANCED_ROOM_ID];
        if (mxRoom.mxSession.crypto)
        {
            if (mxRoom.summary.isEncrypted)
            {
                if (RiotSettings.shared.roomSettingsScreenAdvancedShowEncryptToVerifiedOption)
                {
                    [sectionAdvanced addRowWithTag:ROOM_SETTINGS_ADVANCED_ENCRYPT_TO_VERIFIED];
                }
                [sectionAdvanced addRowWithTag:ROOM_SETTINGS_ADVANCED_ENCRYPTION_ENABLED];
            }
            else
            {
                // Check user's power level to know whether the user is allowed to turn on the encryption mode
                MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
                NSInteger oneSelfPowerLevel = [mxRoomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
                
                if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomEncryption])
                {
                    [sectionAdvanced addRowWithTag:ROOM_SETTINGS_ADVANCED_ENABLE_ENCRYPTION];
                }
                else
                {
                    [sectionAdvanced addRowWithTag:ROOM_SETTINGS_ADVANCED_ENCRYPTION_DISABLED];
                }
            }
        }
        
        sectionAdvanced.headerTitle = [VectorL10n roomDetailsAdvancedSection];
        [tmpSections addObject:sectionAdvanced];
    }
    
    //  update sections
    self.tableViewSections.sections = tmpSections;
}

#pragma mark -

- (void)setSelectedRoomSettingsField:(RoomSettingsViewControllerField)selectedRoomSettingsField
{
    // Check whether the view controller is already embedded inside a navigation controller
    if (self.navigationController)
    {
        [self dismissFirstResponder];
        
        // Check whether user allowed to change room info
        NSDictionary *eventTypes = @{
                                     @(RoomSettingsViewControllerFieldName): kMXEventTypeStringRoomName,
                                     @(RoomSettingsViewControllerFieldTopic): kMXEventTypeStringRoomTopic,
                                     @(RoomSettingsViewControllerFieldAvatar): kMXEventTypeStringRoomAvatar
                                     };
        
        NSString *eventTypeForSelectedField = eventTypes[@(selectedRoomSettingsField)];
        
        if (!eventTypeForSelectedField)
            return;
        
        MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
        NSInteger oneSelfPowerLevel = [mxRoomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
        
        if (oneSelfPowerLevel < [powerLevels minimumPowerLevelForSendingEventAsStateEvent:eventTypeForSelectedField])
            return;
        
        switch (selectedRoomSettingsField)
        {
            case RoomSettingsViewControllerFieldName:
            {
                [self editRoomName];
                break;
            }
            case RoomSettingsViewControllerFieldTopic:
            {
                [self editRoomTopic];
                break;
            }
            case RoomSettingsViewControllerFieldAvatar:
            {
                [self onRoomAvatarTap:nil];
                break;
            }
                
            default:
                break;
        }
    }
    else
    {
        // This selection will be applied when the view controller will become active (see 'viewDidAppear')
        _selectedRoomSettingsField = selectedRoomSettingsField;
    }
}

#pragma mark - private

- (void)editRoomName
{
    if (![nameTextField becomeFirstResponder])
    {
        // Retry asynchronously
        dispatch_async(dispatch_get_main_queue(), ^{
            
            [self editRoomName];
            
        });
    }
}

- (void)editRoomTopic
{
    if (![topicTextView becomeFirstResponder])
    {
        // Retry asynchronously
        dispatch_async(dispatch_get_main_queue(), ^{
            
            [self editRoomTopic];
            
        });
    }
}

- (void)editAddRoomAddress
{
    if (![addAddressTextField becomeFirstResponder])
    {
        // Retry asynchronously
        dispatch_async(dispatch_get_main_queue(), ^{
            
            [self editAddRoomAddress];
            
        });
    }
}

- (void)dismissFirstResponder
{
    if ([topicTextView isFirstResponder])
    {
        [topicTextView resignFirstResponder];
    }
    
    if ([nameTextField isFirstResponder])
    {
        [nameTextField resignFirstResponder];
    }
    
    if ([addAddressTextField isFirstResponder])
    {
        [addAddressTextField resignFirstResponder];
    }
    
    _selectedRoomSettingsField = RoomSettingsViewControllerFieldNone;
}

- (void)startActivityIndicator
{
    // Lock user interaction
    self.tableView.userInteractionEnabled = NO;
    
    // Check whether the current view controller is displayed inside a segmented view controller in order to run the right activity view
    if (self.parentViewController && [self.parentViewController isKindOfClass:SegmentedViewController.class])
    {
        [((SegmentedViewController*)self.parentViewController) startActivityIndicator];
        
        // Force stop the activity view of the view controller
        [self.activityIndicator stopAnimating];
    }
    else
    {
        [super startActivityIndicator];
    }
}

- (void)stopActivityIndicator
{
    // Check local conditions before stop the activity indicator
    if (!pendingOperation && !uploader)
    {
        // Unlock user interaction
        self.tableView.userInteractionEnabled = YES;
        
        // Check whether the current view controller is displayed inside a segmented view controller in order to stop the right activity view
        if (self.parentViewController && [self.parentViewController isKindOfClass:SegmentedViewController.class])
        {
            [((SegmentedViewController*)self.parentViewController) stopActivityIndicator];
            
            // Force stop the activity view of the view controller
            [self.activityIndicator stopAnimating];
        }
        else
        {
            [super stopActivityIndicator];
        }
    }
}

- (void)promptUserToSaveChanges
{
    // ensure that the user understands that the updates will be lost if
    [currentAlert dismissViewControllerAnimated:NO completion:nil];
    
    __weak typeof(self) weakSelf = self;
    
    currentAlert = [UIAlertController alertControllerWithTitle:nil
                                                       message:[VectorL10n roomDetailsSaveChangesPrompt]
                                                preferredStyle:UIAlertControllerStyleAlert];
    
    [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n no]
                                                     style:UIAlertActionStyleDefault
                                                   handler:^(UIAlertAction * action) {
                                                       
                                                       if (weakSelf)
                                                       {
                                                           typeof(self) self = weakSelf;
                                                           self->currentAlert = nil;
                                                           
                                                           [self->updatedItemsDict removeAllObjects];
                                                           
                                                           if (self.delegate)
                                                           {
                                                               [self.delegate roomSettingsViewControllerDidCancel:self];
                                                           }
                                                           else
                                                           {
                                                               [self withdrawViewControllerAnimated:YES completion:nil];
                                                           }
                                                       }
                                                       
                                                   }]];
    
    [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n yes]
                                                     style:UIAlertActionStyleDefault
                                                   handler:^(UIAlertAction * action) {
                                                       
                                                       if (weakSelf)
                                                       {
                                                           typeof(self) self = weakSelf;
                                                           self->currentAlert = nil;
                                                           
                                                           [self onSave:nil];
                                                       }
                                                       
                                                   }]];
    
    [currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCSaveChangesAlert"];
    [self presentViewController:currentAlert animated:YES completion:nil];
}

- (void)promptUserToCopyRoomId:(UILabel*)roomIdLabel
{
    if (roomIdLabel)
    {
        [currentAlert dismissViewControllerAnimated:NO completion:nil];
        
        __weak typeof(self) weakSelf = self;
        
        currentAlert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
        
        [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomDetailsCopyRoomId]
                                                         style:UIAlertActionStyleDefault
                                                       handler:^(UIAlertAction * action) {
                                                           
                                                           if (weakSelf)
                                                           {
                                                               typeof(self) self = weakSelf;
                                                               self->currentAlert = nil;
                                                               
                                                               NSString *roomdId = roomIdLabel.text;
                                                               
                                                               if (roomdId)
                                                               {
                                                                   MXKPasteboardManager.shared.pasteboard.string = roomdId;
                                                               }
                                                               else
                                                               {
                                                                   MXLogDebug(@"[RoomSettingsViewController] Copy room id failed. Room id is nil");
                                                               }
                                                           }
                                                           
                                                       }]];
        
        [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
                                                         style:UIAlertActionStyleCancel
                                                       handler:^(UIAlertAction * action) {
                                                           
                                                           if (weakSelf)
                                                           {
                                                               typeof(self) self = weakSelf;
                                                               self->currentAlert = nil;
                                                           }
                                                           
                                                       }]];
        
        [currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCCopyRoomIdAlert"];
        [currentAlert popoverPresentationController].sourceView = roomIdLabel;
        [currentAlert popoverPresentationController].sourceRect = roomIdLabel.bounds;
        [self presentViewController:currentAlert animated:YES completion:nil];
    }
}

- (void)promptUserOnSelectedRoomAlias:(UILabel*)roomAliasLabel
{
    if (roomAliasLabel)
    {
        [currentAlert dismissViewControllerAnimated:NO completion:nil];
        
        __weak typeof(self) weakSelf = self;
        
        currentAlert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
        
        // Check whether the user is allowed to modify the main address.
        if ([self canSetCanonicalAlias])
        {
            // Compare the selected alias with the current main address
            NSString *currentCanonicalAlias = mxRoomState.canonicalAlias;
            NSString *canonicalAlias;
            
            if (updatedItemsDict[kRoomSettingsCanonicalAliasKey])
            {
                canonicalAlias = updatedItemsDict[kRoomSettingsCanonicalAliasKey];
            }
            else
            {
                canonicalAlias = currentCanonicalAlias;
            }
            
            if (canonicalAlias && [roomAliasLabel.text isEqualToString:canonicalAlias])
            {
                [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomDetailsUnsetMainAddress]
                                                                 style:UIAlertActionStyleDefault
                                                               handler:^(UIAlertAction * action) {
                                                                   
                                                                   if (weakSelf)
                                                                   {
                                                                       typeof(self) self = weakSelf;
                                                                       self->currentAlert = nil;
                                                                       
                                                                       // Prompt user before removing the current main address (use dispatch_async here to not be stuck by the table refresh).
                                                                       dispatch_async(dispatch_get_main_queue(), ^{
                                                                           
                                                                           [self shouldRemoveCanonicalAlias:nil];
                                                                           
                                                                       });
                                                                   }
                                                                   
                                                               }]];
            }
            else
            {
                // Invite user to define this alias as the main room address
                [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomDetailsSetMainAddress]
                                                                 style:UIAlertActionStyleDefault
                                                               handler:^(UIAlertAction * action) {
                                                                   
                                                                   if (weakSelf)
                                                                   {
                                                                       typeof(self) self = weakSelf;
                                                                       self->currentAlert = nil;
                                                                       
                                                                       [self setRoomAliasAsMainAddress:roomAliasLabel.text];
                                                                   }
                                                                   
                                                               }]];
            }
        }
        
        [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomDetailsCopyRoomAddress]
                                                         style:UIAlertActionStyleDefault
                                                       handler:^(UIAlertAction * action) {
                                                           
                                                           if (weakSelf)
                                                           {
                                                               typeof(self) self = weakSelf;
                                                               self->currentAlert = nil;
                                                               
                                                               NSString *roomAlias = roomAliasLabel.text;
                                                               
                                                               if (roomAlias)
                                                               {
                                                                   MXKPasteboardManager.shared.pasteboard.string = roomAlias;
                                                               }
                                                               else
                                                               {
                                                                   MXLogDebug(@"[RoomSettingsViewController] Copy room address failed. Room address is nil");
                                                               }
                                                           }
                                                           
                                                       }]];
        
        [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomDetailsCopyRoomUrl]
                                                         style:UIAlertActionStyleDefault
                                                       handler:^(UIAlertAction * action) {
            
            if (weakSelf)
            {
                typeof(self) self = weakSelf;
                self->currentAlert = nil;
                
                // Create a matrix.to permalink to the room
                
                NSString *permalink = [MXTools permalinkToRoom:roomAliasLabel.text];
                NSURL *url = [NSURL URLWithString:permalink];

                if (url)
                {
                    MXKPasteboardManager.shared.pasteboard.URL = url;
                    [self.view vc_toastWithMessage:VectorL10n.roomEventCopyLinkInfo
                                             image:AssetImages.linkIcon.image
                                          duration:2.0
                                          position:ToastPositionBottom
                                  additionalMargin:0.0];
                }
                else
                {
                    MXLogDebug(@"[RoomSettingsViewController] Copy room URL failed. Room URL is nil");
                }
            }
            
        }]];
        
        // The user can only delete alias they has created, even if the Admin has set it as canonical.
        // So, let the server answer if it's possible to delete an alias.
        [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n delete]
                                                         style:UIAlertActionStyleDefault
                                                       handler:^(UIAlertAction * action) {

                                                           if (weakSelf)
                                                           {
                                                               typeof(self) self = weakSelf;
                                                               self->currentAlert = nil;

                                                               [self removeRoomAlias:roomAliasLabel.text];
                                                           }

                                                       }]];
        
        [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
                                                         style:UIAlertActionStyleCancel
                                                       handler:^(UIAlertAction * action) {
                                                           
                                                           if (weakSelf)
                                                           {
                                                               typeof(self) self = weakSelf;
                                                               self->currentAlert = nil;
                                                           }
                                                           
                                                       }]];
        
        [currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCOnSelectedAliasAlert"];
        [currentAlert popoverPresentationController].sourceView = roomAliasLabel;
        [currentAlert popoverPresentationController].sourceRect = roomAliasLabel.bounds;
        [self presentViewController:currentAlert animated:YES completion:nil];
    }
}

- (void)retrieveActualDirectoryVisibility
{
    if (!mxRoom || actualDirectoryVisibilityRequest)
    {
        return;
    }
    
    // Trigger a new request to check the actual directory visibility
    __weak typeof(self) weakSelf = self;
    
    actualDirectoryVisibilityRequest = [mxRoom directoryVisibility:^(MXRoomDirectoryVisibility directoryVisibility) {
        
        if (weakSelf)
        {
            typeof(self) self = weakSelf;
            self->actualDirectoryVisibilityRequest = nil;
            
            self->actualDirectoryVisibility = directoryVisibility;
            
            // Update the value of the displayed toggle button (if any)
            if (self->directoryVisibilitySwitch)
            {
                // Check a potential user's change before the end of the request
                MXRoomDirectoryVisibility modifiedDirectoryVisibility = self->updatedItemsDict[kRoomSettingsDirectoryKey];
                if (modifiedDirectoryVisibility)
                {
                    if ([modifiedDirectoryVisibility isEqualToString:directoryVisibility])
                    {
                        // The requested change corresponds to the actual settings
                        [self->updatedItemsDict removeObjectForKey:kRoomSettingsDirectoryKey];
                        
                        [self getNavigationItem].rightBarButtonItem.enabled = (self->updatedItemsDict.count != 0);
                    }
                }
                
                self->directoryVisibilitySwitch.on = ([directoryVisibility isEqualToString:kMXRoomDirectoryVisibilityPublic]);
            }
        }
        
    } failure:^(NSError *error) {
        
        MXLogDebug(@"[RoomSettingsViewController] request to get directory visibility failed");
        
        if (weakSelf)
        {
            typeof(self) self = weakSelf;
            self->actualDirectoryVisibilityRequest = nil;
        }
    }];
}

#pragma mark - UITextViewDelegate

- (void)textViewDidBeginEditing:(UITextView *)textView;
{
    if (topicTextView == textView)
    {
        UIView *contentView = topicTextView.superview;
        if (contentView)
        {
            // refresh cell's layout
            [contentView.superview setNeedsLayout];
        }
    }
}

- (void)textViewDidEndEditing:(UITextView *)textView
{
    if (topicTextView == textView)
    {
        UIView *contentView = topicTextView.superview;
        if (contentView)
        {
            // refresh cell's layout
            [contentView.superview setNeedsLayout];
        }
    }
}

- (void)textViewDidChange:(UITextView *)textView
{
    if (topicTextView == textView)
    {
        NSString* currentTopic = mxRoomState.topic;
        
        // Remove white space from both ends
        NSString* topic = [textView.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
        
        // Check whether the topic has been actually changed
        if ((topic || currentTopic) && ([topic isEqualToString:currentTopic] == NO))
        {
            updatedItemsDict[kRoomSettingsTopicKey] = topic ? topic : @"";
        }
        else
        {
            [updatedItemsDict removeObjectForKey:kRoomSettingsTopicKey];
        }
        
        [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
    }
}

#pragma mark - UITextFieldDelegate

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    if (textField == nameTextField)
    {
        nameTextField.textAlignment = NSTextAlignmentLeft;
    }
    else if (textField == addAddressTextField)
    {
        if (textField.text.length == 0)
        {
            textField.text = @"#";
        }
    }
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
    if (textField == nameTextField)
    {
        nameTextField.textAlignment = NSTextAlignmentRight;
    }
    else if (textField == addAddressTextField)
    {
        if (textField.text.length < 2)
        {
            // reset text field
            textField.text = nil;
        }
        else
        {
            // Check whether homeserver suffix should be added
            NSRange range = [textField.text rangeOfString:@":"];
            if (range.location == NSNotFound)
            {
                textField.text = [textField.text stringByAppendingString:self.mainSession.matrixRestClient.homeserverSuffix];
            }
        }
    }
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    // Auto complete room alias
    if (textField == addAddressTextField)
    {
        // Add # if none
        if (!textField.text.length || textField.text.length == range.length)
        {
            if ([string hasPrefix:@"#"] == NO)
            {
                if ([string isEqualToString:@":"])
                {
                    textField.text = [NSString stringWithFormat:@"#%@",self.mainSession.matrixRestClient.homeserverSuffix];
                }
                else
                {
                    textField.text = [NSString stringWithFormat:@"#%@",string];
                }
                return NO;
            }
        }
        else
        {
            // Remove default '#' if the string start with '#'
            if ([string hasPrefix:@"#"] && [textField.text isEqualToString:@"#"])
            {
                textField.text = string;
                return NO;
            }
            // Add homeserver automatically when user adds ':' at the end
            else if (range.location == textField.text.length && [string isEqualToString:@":"])
            {
                textField.text = [textField.text stringByAppendingString:self.mainSession.matrixRestClient.homeserverSuffix];
                return NO;
            }
        }
    }
    return YES;
}

- (BOOL)textFieldShouldClear:(UITextField *)textField
{
    if (textField == addAddressTextField)
    {
        textField.text = @"#";
        return NO;
    }
    return YES;
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    if (textField == nameTextField)
    {
        // Dismiss the keyboard
        [nameTextField resignFirstResponder];
    }
    else if (textField == addAddressTextField)
    {
        // Dismiss the keyboard
        [addAddressTextField resignFirstResponder];
        
        NSString *roomAlias = addAddressTextField.text;
        if (!roomAlias.length || [self addRoomAlias:roomAlias])
        {
            // Reset the input field
            addAddressTextField.text = nil;
        }
    }
    
    return YES;
}

#pragma mark - actions

- (IBAction)onTextFieldUpdate:(UITextField*)textField
{
    if (textField == nameTextField)
    {
        NSString *currentName = mxRoomState.name;
        
        // Remove white space from both ends
        NSString *displayName = [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
        
        // Check whether the name has been actually changed
        if ((displayName || currentName) && ([displayName isEqualToString:currentName] == NO))
        {
            updatedItemsDict[kRoomSettingsNameKey] = displayName ? displayName : @"";
        }
        else
        {
            [updatedItemsDict removeObjectForKey:kRoomSettingsNameKey];
        }
        
        [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
    }
}

- (void)didUpdateRules:(NSNotification *)notif
{
    [self refreshRoomSettings];
}

- (IBAction)onCancel:(id)sender
{
    [self dismissFirstResponder];
    
    // Check whether some changes have been done
    if (updatedItemsDict.count)
    {
        [self promptUserToSaveChanges];
    }
    else
    {
        if (self.delegate)
        {
            [self.delegate roomSettingsViewControllerDidCancel:self];
        }
        else
        {
            [self withdrawViewControllerAnimated:YES completion:nil];
        }
    }
}

- (void)onSaveFailed:(NSString*)message withKeys:(NSArray<NSString *>*)keys
{
    __weak typeof(self) weakSelf = self;
    
    [currentAlert dismissViewControllerAnimated:NO completion:nil];
    
    currentAlert = [UIAlertController alertControllerWithTitle:nil message:message preferredStyle:UIAlertControllerStyleAlert];
    
    [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
                                                     style:UIAlertActionStyleCancel
                                                   handler:^(UIAlertAction * action) {
                                                       
                                                       if (weakSelf)
                                                       {
                                                           typeof(self) self = weakSelf;
                                                           self->currentAlert = nil;
                                                           
                                                           // Discard related change
                                                           for (NSString *key in keys)
                                                           {
                                                               [self->updatedItemsDict removeObjectForKey:key];
                                                           }
                                                           
                                                           // Save anything else
                                                           [self onSave:nil];
                                                       }
                                                       
                                                   }]];
    
    [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n retry]
                                                     style:UIAlertActionStyleDefault
                                                   handler:^(UIAlertAction * action) {
                                                       
                                                       if (weakSelf)
                                                       {
                                                           typeof(self) self = weakSelf;
                                                           self->currentAlert = nil;
                                                           
                                                           [self onSave:nil];
                                                       }
                                                       
                                                   }]];
    
    [currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCSaveChangesFailedAlert"];
    [self presentViewController:currentAlert animated:YES completion:nil];
}

- (IBAction)onSave:(id)sender
{
    if (updatedItemsDict.count)
    {
        [self startActivityIndicator];
        
        __weak typeof(self) weakSelf = self;
        
        // check if there is some updates related to room state
        if (mxRoomState)
        {
            if (updatedItemsDict[kRoomSettingsAvatarKey])
            {
                // Retrieve the current picture and make sure its orientation is up
                UIImage *updatedPicture = [MXKTools forceImageOrientationUp:updatedItemsDict[kRoomSettingsAvatarKey]];
                
                // Upload picture
                uploader = [MXMediaManager prepareUploaderWithMatrixSession:mxRoom.mxSession initialRange:0 andRange:1.0];
                
                [uploader uploadData:UIImageJPEGRepresentation(updatedPicture, 0.5) filename:nil mimeType:@"image/jpeg" success:^(NSString *url) {
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->uploader = nil;
                        
                        [self->updatedItemsDict removeObjectForKey:kRoomSettingsAvatarKey];
                        self->updatedItemsDict[kRoomSettingsAvatarURLKey] = url;
                        
                        [self onSave:nil];
                    }
                    
                } failure:^(NSError *error) {
                    
                    MXLogDebug(@"[RoomSettingsViewController] Image upload failed");
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->uploader = nil;
                        
                        dispatch_async(dispatch_get_main_queue(), ^{
                            
                            NSString* message = error.localizedDescription;
                            if (!message.length)
                            {
                                message = [VectorL10n roomDetailsFailToUpdateAvatar];
                            }
                            [self onSaveFailed:message withKeys:@[kRoomSettingsAvatarKey]];
                            
                        });
                    }
                    
                }];
                
                return;
            }
            
            NSString* photoUrl = updatedItemsDict[kRoomSettingsAvatarURLKey];
            if (photoUrl)
            {
                pendingOperation = [mxRoom setAvatar:photoUrl success:^{
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        [self->updatedItemsDict removeObjectForKey:kRoomSettingsAvatarURLKey];
                        [self onSave:nil];
                    }
                    
                } failure:^(NSError *error) {
                    
                    MXLogDebug(@"[RoomSettingsViewController] Failed to update the room avatar");
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        
                        dispatch_async(dispatch_get_main_queue(), ^{
                            
                            NSString* message = error.localizedDescription;
                            if (!message.length)
                            {
                                message = [VectorL10n roomDetailsFailToUpdateAvatar];
                            }
                            [self onSaveFailed:message withKeys:@[kRoomSettingsAvatarURLKey]];
                            
                        });
                    }
                    
                }];
                
                return;
            }
            
            // has a new room name
            NSString* roomName = updatedItemsDict[kRoomSettingsNameKey];
            if (roomName)
            {
                pendingOperation = [mxRoom setName:roomName success:^{
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        [self->updatedItemsDict removeObjectForKey:kRoomSettingsNameKey];
                        [self onSave:nil];
                    }
                    
                } failure:^(NSError *error) {
                    
                    MXLogDebug(@"[RoomSettingsViewController] Rename room failed");
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        
                        dispatch_async(dispatch_get_main_queue(), ^{
                            
                            NSString* message = error.localizedDescription;
                            if (!message.length)
                            {
                                message = [VectorL10n roomDetailsFailToUpdateRoomName];
                            }
                            [self onSaveFailed:message withKeys:@[kRoomSettingsNameKey]];
                            
                        });
                    }
                    
                }];
                
                return;
            }
            
            // has a new room topic
            NSString* roomTopic = updatedItemsDict[kRoomSettingsTopicKey];
            if (roomTopic)
            {
                pendingOperation = [mxRoom setTopic:roomTopic success:^{
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        [self->updatedItemsDict removeObjectForKey:kRoomSettingsTopicKey];
                        [self onSave:nil];
                    }
                    
                } failure:^(NSError *error) {
                    
                    MXLogDebug(@"[RoomSettingsViewController] Rename topic failed");
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        
                        dispatch_async(dispatch_get_main_queue(), ^{
                            
                            NSString* message = error.localizedDescription;
                            if (!message.length)
                            {
                                message = [VectorL10n roomDetailsFailToUpdateTopic];
                            }
                            [self onSaveFailed:message withKeys:@[kRoomSettingsTopicKey]];
                            
                        });
                    }
                    
                }];
                
                return;
            }
            
            // Room guest access
            MXRoomGuestAccess guestAccess = updatedItemsDict[kRoomSettingsGuestAccessKey];
            if (guestAccess)
            {
                pendingOperation = [mxRoom setGuestAccess:guestAccess success:^{
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        [self->updatedItemsDict removeObjectForKey:kRoomSettingsGuestAccessKey];
                        [self onSave:nil];
                    }
                    
                } failure:^(NSError *error) {
                    
                    MXLogDebug(@"[RoomSettingsViewController] Update guest access failed");
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        
                        dispatch_async(dispatch_get_main_queue(), ^{
                            
                            NSString* message = error.localizedDescription;
                            if (!message.length)
                            {
                                message = [VectorL10n roomDetailsFailToUpdateRoomGuestAccess];
                            }
                            [self onSaveFailed:message withKeys:@[kRoomSettingsGuestAccessKey]];
                            
                        });
                    }
                    
                }];
                
                return;
            }
            
            // Room join rule
            MXRoomJoinRule joinRule = updatedItemsDict[kRoomSettingsJoinRuleKey];
            if (joinRule)
            {
                pendingOperation = [mxRoom setJoinRule:joinRule success:^{
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        [self->updatedItemsDict removeObjectForKey:kRoomSettingsJoinRuleKey];
                        [self onSave:nil];
                    }
                    
                } failure:^(NSError *error) {
                    
                    MXLogDebug(@"[RoomSettingsViewController] Update join rule failed");
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        
                        dispatch_async(dispatch_get_main_queue(), ^{
                            
                            NSString* message = error.localizedDescription;
                            if (!message.length)
                            {
                                message = [VectorL10n roomDetailsFailToUpdateRoomJoinRule];
                            }
                            [self onSaveFailed:message withKeys:@[kRoomSettingsJoinRuleKey]];
                            
                        });
                    }
                    
                }];
                
                return;
            }
            
            // History visibility
            MXRoomHistoryVisibility visibility = updatedItemsDict[kRoomSettingsHistoryVisibilityKey];
            if (visibility)
            {
                pendingOperation = [mxRoom setHistoryVisibility:visibility success:^{
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        [self->updatedItemsDict removeObjectForKey:kRoomSettingsHistoryVisibilityKey];
                        [self onSave:nil];
                    }
                    
                } failure:^(NSError *error) {
                    
                    MXLogDebug(@"[RoomSettingsViewController] Update history visibility failed");
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        
                        dispatch_async(dispatch_get_main_queue(), ^{
                            
                            NSString* message = error.localizedDescription;
                            if (!message.length)
                            {
                                message = [VectorL10n roomDetailsFailToUpdateHistoryVisibility];
                            }
                            [self onSaveFailed:message withKeys:@[kRoomSettingsHistoryVisibilityKey]];
                            
                        });
                    }
                    
                }];
                
                return;
            }
            
            // Room addresses
            NSMutableArray<NSString *> *aliases = updatedItemsDict[kRoomSettingsNewAliasesKey];
            if (aliases.count)
            {
                NSString *roomAlias = aliases.firstObject;
                
                pendingOperation = [mxRoom addAlias:roomAlias success:^{
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        
                        if (aliases.count > 1)
                        {
                            [aliases removeObjectAtIndex:0];
                            self->updatedItemsDict[kRoomSettingsNewAliasesKey] = aliases;
                        }
                        else
                        {
                            [self->updatedItemsDict removeObjectForKey:kRoomSettingsNewAliasesKey];
                        }
                        
                        [self onSave:nil];
                    }
                    
                } failure:^(NSError *error) {
                    
                    MXLogDebug(@"[RoomSettingsViewController] Add room aliases failed");
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        
                        dispatch_async(dispatch_get_main_queue(), ^{
                            
                            NSString* message = error.localizedDescription;
                            if (!message.length)
                            {
                                message = [VectorL10n roomDetailsFailToAddRoomAliases];
                            }
                            [self onSaveFailed:message withKeys:@[kRoomSettingsNewAliasesKey]];
                            
                        });
                    }
                    
                }];
                
                return;
            }
            
            aliases = updatedItemsDict[kRoomSettingsRemovedAliasesKey];
            if (aliases.count)
            {
                NSString *roomAlias = aliases.firstObject;
                
                pendingOperation = [mxRoom removeAlias:roomAlias success:^{
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        
                        if (aliases.count > 1)
                        {
                            [aliases removeObjectAtIndex:0];
                            self->updatedItemsDict[kRoomSettingsRemovedAliasesKey] = aliases;
                        }
                        else
                        {
                            [self->updatedItemsDict removeObjectForKey:kRoomSettingsRemovedAliasesKey];
                        }
                        
                        [self onSave:nil];
                    }
                    
                } failure:^(NSError *error) {
                    
                    MXLogDebug(@"[RoomSettingsViewController] Remove room aliases failed");
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        
                        dispatch_async(dispatch_get_main_queue(), ^{
                            
                            NSString* message = error.localizedDescription;
                            if (!message.length)
                            {
                                message = [VectorL10n roomDetailsFailToRemoveRoomAliases];
                            }
                            [self onSaveFailed:message withKeys:@[kRoomSettingsRemovedAliasesKey]];
                            
                        });
                    }
                    
                }];
                
                return;
            }
            
            NSString* canonicalAlias = updatedItemsDict[kRoomSettingsCanonicalAliasKey];
            if (canonicalAlias)
            {
                pendingOperation = [mxRoom setCanonicalAlias:canonicalAlias success:^{
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        [self->updatedItemsDict removeObjectForKey:kRoomSettingsCanonicalAliasKey];
                        [self onSave:nil];
                    }
                    
                } failure:^(NSError *error) {
                    
                    MXLogDebug(@"[RoomSettingsViewController] Update canonical alias failed");
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        self->pendingOperation = nil;
                        
                        dispatch_async(dispatch_get_main_queue(), ^{
                            
                            NSString* message = error.localizedDescription;
                            if (!message.length)
                            {
                                message = [VectorL10n roomDetailsFailToUpdateRoomCanonicalAlias];
                            }
                            [self onSaveFailed:message withKeys:@[kRoomSettingsCanonicalAliasKey]];
                            
                        });
                    }
                    
                }];
                
                return;
            }
        }
        
        // Update here other room settings
        NSString *roomTag = updatedItemsDict[kRoomSettingsTagKey];
        if (roomTag)
        {
            if (!roomTag.length)
            {
                roomTag = nil;
            }
            
            [mxRoom setRoomTag:roomTag completion:^{
                
                if (weakSelf)
                {
                    typeof(self) self = weakSelf;
                    
                    [self->updatedItemsDict removeObjectForKey:kRoomSettingsTagKey];
                    [self onSave:nil];
                }
                
            }];
            
            return;
        }
        
        if (updatedItemsDict[kRoomSettingsMuteNotifKey])
        {
            if (((NSNumber*) updatedItemsDict[kRoomSettingsMuteNotifKey]).boolValue)
            {
                [mxRoom mentionsOnly:^{
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        [self->updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey];
                        [self onSave:nil];
                    }
                    
                }];
            }
            else
            {
                [mxRoom allMessages:^{
                    
                    if (weakSelf)
                    {
                        typeof(self) self = weakSelf;
                        
                        [self->updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey];
                        [self onSave:nil];
                    }
                    
                }];
            }
            return;
        }
        
        if (updatedItemsDict[kRoomSettingsDirectChatKey])
        {
            pendingOperation = [mxRoom setIsDirect:((NSNumber*) updatedItemsDict[kRoomSettingsDirectChatKey]).boolValue withUserId:nil success:^{
                
                if (weakSelf)
                {
                    typeof(self) self = weakSelf;
                    
                    self->pendingOperation = nil;
                    [self->updatedItemsDict removeObjectForKey:kRoomSettingsDirectChatKey];
                    [self onSave:nil];
                }
                
            }                              failure:^(NSError *error) {
                
                MXLogDebug(@"[RoomSettingsViewController] Altering DMness failed");
                
                if (weakSelf)
                {
                    typeof(self) self = weakSelf;
                    
                    self->pendingOperation = nil;
                    
                    dispatch_async(dispatch_get_main_queue(), ^{
                        
                        NSString* message = error.localizedDescription;
                        if (!message.length)
                        {
                            message = [VectorL10n roomDetailsFailToUpdateRoomDirect];
                        }
                        [self onSaveFailed:message withKeys:@[kRoomSettingsDirectChatKey]];
                        
                    });
                }
                
            }];
            return;
        }
        
        // Room directory visibility
        MXRoomDirectoryVisibility directoryVisibility = updatedItemsDict[kRoomSettingsDirectoryKey];
        if (directoryVisibility)
        {
            [mxRoom setDirectoryVisibility:directoryVisibility success:^{
                
                if (weakSelf)
                {
                    typeof(self) self = weakSelf;
                    
                    [self->updatedItemsDict removeObjectForKey:kRoomSettingsDirectoryKey];
                    [self onSave:nil];
                }
                
            } failure:^(NSError *error) {
                
                MXLogDebug(@"[RoomSettingsViewController] Update room directory visibility failed");
                
                if (weakSelf)
                {
                    typeof(self) self = weakSelf;
                    
                    self->pendingOperation = nil;
                    
                    dispatch_async(dispatch_get_main_queue(), ^{
                        
                        NSString* message = error.localizedDescription;
                        if (!message.length)
                        {
                            message = [VectorL10n roomDetailsFailToUpdateRoomDirectoryVisibility];
                        }
                        [self onSaveFailed:message withKeys:@[kRoomSettingsDirectoryKey]];
                        
                    });
                }
                
            }];
            
            return;
        }
        
        // Room encryption
        if (updatedItemsDict[kRoomSettingsEncryptionKey])
        {
            pendingOperation = [mxRoom enableEncryptionWithAlgorithm:kMXCryptoMegolmAlgorithm success:^{
                
                if (weakSelf)
                {
                    typeof(self) self = weakSelf;
                    
                    self->pendingOperation = nil;
                    
                    [self->updatedItemsDict removeObjectForKey:kRoomSettingsEncryptionKey];
                    [self onSave:nil];
                }
                
            } failure:^(NSError *error) {
                
                MXLogDebug(@"[RoomSettingsViewController] Enabling encrytion failed. Error: %@", error);
                
                if (weakSelf)
                {
                    typeof(self) self = weakSelf;
                    
                    self->pendingOperation = nil;
                    
                    dispatch_async(dispatch_get_main_queue(), ^{
                        
                        NSString* message = error.localizedDescription;
                        if (!message.length)
                        {
                            message = [VectorL10n roomDetailsFailToEnableEncryption];
                        }
                        [self onSaveFailed:message withKeys:@[kRoomSettingsEncryptionKey]];
                        
                    });
                }
                
            }];
            
            return;
        }
        
        // Room settings on blacklist unverified devices
        if (updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey])
        {
            BOOL blacklistUnverifiedDevices = [((NSNumber*)updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey]) boolValue];
            [mxRoom.mxSession.crypto setBlacklistUnverifiedDevicesInRoom:mxRoom.roomId blacklist:blacklistUnverifiedDevices];
        }
    }
    
    [self getNavigationItem].rightBarButtonItem.enabled = NO;
    
    [self stopActivityIndicator];
    
    if (self.delegate)
    {
        [self.delegate roomSettingsViewControllerDidComplete:self];
    }
    else
    {
        [self withdrawViewControllerAnimated:YES completion:nil];
    }
}

#pragma mark - UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return _tableViewSections.sections.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    Section *sectionObject = [_tableViewSections sectionAtIndex:section];
    return sectionObject.rows.count;
}

- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    Section *sectionObject = [_tableViewSections sectionAtIndex:section];
    return sectionObject.headerTitle;
}

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
    if ([view isKindOfClass:UITableViewHeaderFooterView.class])
    {
        // Customize label style
        UITableViewHeaderFooterView *tableViewHeaderFooterView = (UITableViewHeaderFooterView*)view;
        tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
        tableViewHeaderFooterView.textLabel.font = [UIFont systemFontOfSize:15];
        tableViewHeaderFooterView.contentView.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSIndexPath *tagsIndexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
    NSInteger section = tagsIndexPath.section;
    NSInteger row = tagsIndexPath.row;

    if (section == SECTION_TAG_MAIN)
    {
        if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC)
        {
            return ROOM_TOPIC_CELL_HEIGHT;
        }
    }
    
    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSIndexPath *tagsIndexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
    NSInteger section = tagsIndexPath.section;
    NSInteger row = tagsIndexPath.row;
    
    UITableViewCell* cell;
    
    // Check user's power level to know which settings are editable.
    MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
    NSInteger oneSelfPowerLevel = [mxRoomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
    
    // general settings
    if (section == SECTION_TAG_MAIN)
    {
        if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS)
        {
            MXKTableViewCellWithLabelAndSwitch *roomNotifCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];

            [roomNotifCell.mxkSwitch addTarget:self action:@selector(toggleRoomNotification:) forControlEvents:UIControlEventValueChanged];
            
            roomNotifCell.mxkLabel.text = [VectorL10n roomDetailsMuteNotifs];
            
            if (updatedItemsDict[kRoomSettingsMuteNotifKey])
            {
                roomNotifCell.mxkSwitch.on = ((NSNumber*) updatedItemsDict[kRoomSettingsMuteNotifKey]).boolValue;
            }
            else
            {
                roomNotifCell.mxkSwitch.on = mxRoom.isMute || mxRoom.isMentionsOnly;
            }
            
            cell = roomNotifCell;
        }
        else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_DIRECT_CHAT)
        {
            MXKTableViewCellWithLabelAndSwitch *roomDirectChat = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
            
            [roomDirectChat.mxkSwitch addTarget:self action:@selector(toggleDirectChat:) forControlEvents:UIControlEventValueChanged];
            
            roomDirectChat.mxkLabel.text = [VectorL10n roomDetailsDirectChat];
            
            if (updatedItemsDict[kRoomSettingsDirectChatKey])
            {
                roomDirectChat.mxkSwitch.on = ((NSNumber*) updatedItemsDict[kRoomSettingsDirectChatKey]).boolValue;
            }
            else
            {
                roomDirectChat.mxkSwitch.on = mxRoom.isDirect;
            }
            
            cell = roomDirectChat;
        }
        else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO)
        {
            MXKTableViewCellWithLabelAndMXKImageView *roomPhotoCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndMXKImageView defaultReuseIdentifier] forIndexPath:indexPath];
            
            roomPhotoCell.mxkLabelLeadingConstraint.constant = tableView.vc_separatorInset.left;
            roomPhotoCell.mxkImageViewTrailingConstraint.constant = 10;
            
            roomPhotoCell.mxkImageViewWidthConstraint.constant = roomPhotoCell.mxkImageViewHeightConstraint.constant = 30;
            
            roomPhotoCell.mxkImageViewDisplayBoxType = MXKTableViewCellDisplayBoxTypeCircle;
            
            // Handle tap on avatar to update it
            if (!roomPhotoCell.mxkImageView.gestureRecognizers.count)
            {
                UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onRoomAvatarTap:)];
                [roomPhotoCell.mxkImageView addGestureRecognizer:tap];
            }
            
            roomPhotoCell.mxkImageView.defaultBackgroundColor = [UIColor clearColor];
            
            if (mxRoom.isDirect)
            {
                roomPhotoCell.mxkLabel.text = [VectorL10n roomDetailsPhotoForDm];
            }
            else
            {
                roomPhotoCell.mxkLabel.text = [VectorL10n roomDetailsPhoto];
            }
            roomPhotoCell.mxkLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
            
            if (updatedItemsDict[kRoomSettingsAvatarKey])
            {
                roomPhotoCell.mxkImageView.image = (UIImage*) updatedItemsDict[kRoomSettingsAvatarKey];
            }
            else
            {
                [mxRoom.summary setRoomAvatarImageIn:roomPhotoCell.mxkImageView];
                
                roomPhotoCell.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomAvatar]);
                roomPhotoCell.mxkImageView.alpha = roomPhotoCell.userInteractionEnabled ? 1.0f : 0.5f;
            }
            
            cell = roomPhotoCell;
        }
        else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC)
        {
            TableViewCellWithLabelAndLargeTextView *roomTopicCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsTopicCellViewIdentifier forIndexPath:indexPath];
            
            roomTopicCell.labelLeadingConstraint.constant = tableView.vc_separatorInset.left;
            
            roomTopicCell.label.text = [VectorL10n roomDetailsTopic];
            
            topicTextView = roomTopicCell.textView;
            
            if (updatedItemsDict[kRoomSettingsTopicKey])
            {
                topicTextView.text = (NSString*) updatedItemsDict[kRoomSettingsTopicKey];
            }
            else
            {
                topicTextView.text = mxRoomState.topic;
            }
            
            topicTextView.tintColor = ThemeService.shared.theme.tintColor;
            topicTextView.font = [UIFont systemFontOfSize:15];
            topicTextView.bounces = NO;
            topicTextView.delegate = self;
            
            // disable the edition if the user cannot update it
            topicTextView.editable = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomTopic]);
            topicTextView.textColor = ThemeService.shared.theme.textSecondaryColor;
            
            topicTextView.keyboardAppearance = ThemeService.shared.theme.keyboardAppearance;
            
            cell = roomTopicCell;
        }
        else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_NAME)
        {
            MXKTableViewCellWithLabelAndTextField *roomNameCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsNameCellViewIdentifier forIndexPath:indexPath];
            
            roomNameCell.mxkLabelLeadingConstraint.constant = tableView.vc_separatorInset.left;
            roomNameCell.mxkTextFieldLeadingConstraint.constant = 16;
            roomNameCell.mxkTextFieldTrailingConstraint.constant = 15;
            
            if (mxRoom.isDirect)
            {
                roomNameCell.mxkLabel.text = [VectorL10n roomDetailsRoomNameForDm];
            }
            else
            {
                roomNameCell.mxkLabel.text = [VectorL10n roomDetailsRoomName];
            }
            roomNameCell.mxkLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
            
            roomNameCell.accessoryType = UITableViewCellAccessoryNone;
            roomNameCell.accessoryView = nil;
            
            nameTextField = roomNameCell.mxkTextField;
            
            nameTextField.tintColor = ThemeService.shared.theme.tintColor;
            nameTextField.font = [UIFont systemFontOfSize:17];
            nameTextField.borderStyle = UITextBorderStyleNone;
            nameTextField.textAlignment = NSTextAlignmentRight;
            nameTextField.delegate = self;
            
            if (updatedItemsDict[kRoomSettingsNameKey])
            {
                nameTextField.text = (NSString*) updatedItemsDict[kRoomSettingsNameKey];
            }
            else
            {
                nameTextField.text = mxRoomState.name;
            }
            
            // disable the edition if the user cannot update it
            nameTextField.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomName]);
            nameTextField.textColor = ThemeService.shared.theme.textSecondaryColor;
            
            // Add a "textFieldDidChange" notification method to the text field control.
            [nameTextField addTarget:self action:@selector(onTextFieldUpdate:) forControlEvents:UIControlEventEditingChanged];
            
            cell = roomNameCell;
        }
        else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_TAG)
        {
            if (RiotSettings.shared.roomSettingsScreenShowLowPriorityOption)
            {
                //  show a muti-checkbox cell
                roomTagCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithCheckBoxes defaultReuseIdentifier] forIndexPath:indexPath];
                roomTagCell.mainContainerLeadingConstraint.constant = tableView.vc_separatorInset.left;
                roomTagCell.checkBoxesNumber = 2;
                roomTagCell.allowsMultipleSelection = NO;
                roomTagCell.delegate = self;
                
                NSArray *labels = roomTagCell.labels;
                UILabel *label;
                label = labels[0];
                label.textColor = ThemeService.shared.theme.textPrimaryColor;
                label.text = [VectorL10n roomDetailsFavouriteTag];
                label = labels[1];
                label.textColor = ThemeService.shared.theme.textPrimaryColor;
                label.text = [VectorL10n roomDetailsLowPriorityTag];
                
                if (updatedItemsDict[kRoomSettingsTagKey])
                {
                    NSString *roomTag = updatedItemsDict[kRoomSettingsTagKey];
                    if ([roomTag isEqualToString:kMXRoomTagFavourite])
                    {
                        [roomTagCell setCheckBoxValue:YES atIndex:0];
                    }
                    else if ([roomTag isEqualToString:kMXRoomTagLowPriority])
                    {
                        [roomTagCell setCheckBoxValue:YES atIndex:1];
                    }
                }
                else
                {
                    if (mxRoom.accountData.tags[kMXRoomTagFavourite] != nil)
                    {
                        [roomTagCell setCheckBoxValue:YES atIndex:0];
                    }
                    else if (mxRoom.accountData.tags[kMXRoomTagLowPriority] != nil)
                    {
                        [roomTagCell setCheckBoxValue:YES atIndex:1];
                    }
                }
                
                cell = roomTagCell;
            }
            else
            {
                //  use a switch cell
                MXKTableViewCellWithLabelAndSwitch *favoriteCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
                
                [favoriteCell.mxkSwitch addTarget:self action:@selector(toggleFavorite:) forControlEvents:UIControlEventValueChanged];
                
                favoriteCell.mxkLabel.text = [VectorL10n roomDetailsFavouriteTag];
                
                if ([updatedItemsDict[kRoomSettingsTagKey] isEqualToString:kMXRoomTagFavourite])
                {
                    favoriteCell.mxkSwitch.on = ((NSNumber*) updatedItemsDict[kMXRoomTagFavourite]).boolValue;
                }
                else
                {
                    favoriteCell.mxkSwitch.on = mxRoom.accountData.tags[kMXRoomTagFavourite] != nil;
                }
                
                cell = favoriteCell;
            }
        }
    }
    else if (section == SECTION_TAG_ACCESS)
    {
        if (row == ROOM_SETTINGS_ROOM_ACCESS_DIRECTORY_VISIBILITY)
        {
            MXKTableViewCellWithLabelAndSwitch *directoryToggleCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
            
            if (mxRoom.isDirect)
            {
                directoryToggleCell.mxkLabel.text = [VectorL10n roomDetailsAccessSectionDirectoryToggleForDm];
            }
            else
            {
                directoryToggleCell.mxkLabel.text = [VectorL10n roomDetailsAccessSectionDirectoryToggle];
            }
            
            [directoryToggleCell.mxkSwitch addTarget:self action:@selector(toggleDirectoryVisibility:) forControlEvents:UIControlEventValueChanged];
            
            if (updatedItemsDict[kRoomSettingsDirectoryKey])
            {
                directoryToggleCell.mxkSwitch.on = ((NSNumber*) updatedItemsDict[kRoomSettingsDirectoryKey]).boolValue;
            }
            else
            {
                // Use the last retrieved value if any
                directoryToggleCell.mxkSwitch.on = actualDirectoryVisibility ? [actualDirectoryVisibility isEqualToString:kMXRoomDirectoryVisibilityPublic] : NO;
            }
            
            // Check whether the user can change this option
            directoryToggleCell.mxkSwitch.enabled = (oneSelfPowerLevel >= powerLevels.stateDefault);
            
            // Store the switch to be able to update it
            directoryVisibilitySwitch = directoryToggleCell.mxkSwitch;
            
            cell = directoryToggleCell;
        }
        else if (row == ROOM_SETTINGS_ROOM_ACCESS_MISSING_ADDRESS_WARNING)
        {
            cell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsWarningCellViewIdentifier forIndexPath:indexPath];
            
            cell.textLabel.font = [UIFont systemFontOfSize:17];
            cell.textLabel.textColor = ThemeService.shared.theme.warningColor;
            cell.textLabel.numberOfLines = 0;
            cell.accessoryView = nil;
            cell.accessoryType = UITableViewCellAccessoryNone;
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
            cell.textLabel.text = [VectorL10n roomDetailsAccessSectionNoAddressWarning];
        }
        else if (row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ACCESS)
        {
            TitleAndRightDetailTableViewCell *roomAccessCell = [tableView dequeueReusableCellWithIdentifier:[TitleAndRightDetailTableViewCell defaultReuseIdentifier] forIndexPath:indexPath];
                        
            // Retrieve the potential updated values for joinRule and guestAccess
            NSString *joinRule = updatedItemsDict[kRoomSettingsJoinRuleKey];
            NSString *guestAccess = updatedItemsDict[kRoomSettingsGuestAccessKey];
            
            // Use the actual values if no change is pending
            if (!joinRule)
            {
                joinRule = mxRoomState.joinRule;
            }
            if (!guestAccess)
            {
                guestAccess = mxRoomState.guestAccess;
            }
            
            roomAccessCell.titleLabel.text = [VectorL10n roomDetailsAccessRowTitle];
            NSString *access = VectorL10n.private;
            if ([joinRule isEqualToString:kMXRoomJoinRulePublic])
            {
                access = VectorL10n.public;
            }
            else if ([joinRule isEqualToString:kMXRoomJoinRuleRestricted])
            {
                access = VectorL10n.createRoomTypeRestricted;
            }
            roomAccessCell.detailLabel.text = access;

            // Check whether the user can change this option
            roomAccessCell.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomJoinRules]);

            cell = roomAccessCell;
        }
        else
        {
            TableViewCellWithCheckBoxAndLabel *roomAccessCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithCheckBoxAndLabel defaultReuseIdentifier] forIndexPath:indexPath];
            
            roomAccessCell.checkBoxLeadingConstraint.constant = tableView.vc_separatorInset.left;
            
            // Retrieve the potential updated values for joinRule and guestAccess
            NSString *joinRule = updatedItemsDict[kRoomSettingsJoinRuleKey];
            NSString *guestAccess = updatedItemsDict[kRoomSettingsGuestAccessKey];
            
            // Use the actual values if no change is pending
            if (!joinRule)
            {
                joinRule = mxRoomState.joinRule;
            }
            if (!guestAccess)
            {
                guestAccess = mxRoomState.guestAccess;
            }

            // Check whether the user can change this option
            roomAccessCell.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomJoinRules]);
            roomAccessCell.checkBox.alpha = roomAccessCell.userInteractionEnabled ? 1.0f : 0.5f;
            
            cell = roomAccessCell;
        }
    }
    else if (section == SECTION_TAG_PROMOTION)
    {
        if (row == ROOM_SETTINGS_ROOM_ACCESS_DIRECTORY_VISIBILITY)
        {
            MXKTableViewCellWithLabelAndSwitch *directoryToggleCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
            
            if (mxRoom.isDirect)
            {
                directoryToggleCell.mxkLabel.text = [VectorL10n roomDetailsAccessSectionDirectoryToggleForDm];
            }
            else
            {
                directoryToggleCell.mxkLabel.text = [VectorL10n roomDetailsAccessSectionDirectoryToggle];
            }
            
            [directoryToggleCell.mxkSwitch addTarget:self action:@selector(toggleDirectoryVisibility:) forControlEvents:UIControlEventValueChanged];
            
            if (updatedItemsDict[kRoomSettingsDirectoryKey])
            {
                directoryToggleCell.mxkSwitch.on = ((NSNumber*) updatedItemsDict[kRoomSettingsDirectoryKey]).boolValue;
            }
            else
            {
                // Use the last retrieved value if any
                directoryToggleCell.mxkSwitch.on = actualDirectoryVisibility ? [actualDirectoryVisibility isEqualToString:kMXRoomDirectoryVisibilityPublic] : NO;
            }
            
            // Check whether the user can change this option
            directoryToggleCell.mxkSwitch.enabled = (oneSelfPowerLevel >= powerLevels.stateDefault);
            
            // Store the switch to be able to update it
            directoryVisibilitySwitch = directoryToggleCell.mxkSwitch;
            
            cell = directoryToggleCell;
        }
        else if (row == ROOM_SETTINGS_ROOM_PROMOTE_SECTION_ROW_SUGGEST)
        {
            TitleAndRightDetailTableViewCell *roomSuggestionCell = [tableView dequeueReusableCellWithIdentifier:[TitleAndRightDetailTableViewCell defaultReuseIdentifier] forIndexPath:indexPath];
                        
            roomSuggestionCell.titleLabel.text = [VectorL10n roomDetailsPromoteRoomSuggestTitle];
            roomSuggestionCell.detailLabel.text = [self.mainSession.spaceService directParentIdsOfRoomWithId:self.roomId whereRoomIsSuggested:YES].count ? [VectorL10n on] : [VectorL10n off];

            // Check whether the user can change this option
            roomSuggestionCell.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomJoinRules]);

            cell = roomSuggestionCell;
        }
    }
    else if (section == SECTION_TAG_HISTORY)
    {
        TableViewCellWithCheckBoxAndLabel *historyVisibilityCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithCheckBoxAndLabel defaultReuseIdentifier] forIndexPath:indexPath];
        
        historyVisibilityCell.checkBoxLeadingConstraint.constant = tableView.vc_separatorInset.left;
        
        // Retrieve first the potential updated value for history visibility
        NSString *visibility = updatedItemsDict[kRoomSettingsHistoryVisibilityKey];
        
        // Use the actual value if no change is pending
        if (!visibility)
        {
            visibility = mxRoomState.historyVisibility;
        }
        
        if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_ANYONE)
        {
            historyVisibilityCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle;
            historyVisibilityCell.label.text = [VectorL10n roomDetailsHistorySectionAnyone];
            
            historyVisibilityCell.enabled = ([visibility isEqualToString:kMXRoomHistoryVisibilityWorldReadable]);
            
            historyVisibilityTickCells[kMXRoomHistoryVisibilityWorldReadable] = historyVisibilityCell;
        }
        else if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY)
        {
            historyVisibilityCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle;
            historyVisibilityCell.label.text = [VectorL10n roomDetailsHistorySectionMembersOnly];
            
            historyVisibilityCell.enabled = ([visibility isEqualToString:kMXRoomHistoryVisibilityShared]);
            
            historyVisibilityTickCells[kMXRoomHistoryVisibilityShared] = historyVisibilityCell;
        }
        else if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_INVITED)
        {
            historyVisibilityCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle;
            historyVisibilityCell.label.text = [VectorL10n roomDetailsHistorySectionMembersOnlySinceInvited];
            
            historyVisibilityCell.enabled = ([visibility isEqualToString:kMXRoomHistoryVisibilityInvited]);
            
            historyVisibilityTickCells[kMXRoomHistoryVisibilityInvited] = historyVisibilityCell;
        }
        else if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_JOINED)
        {
            historyVisibilityCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle;
            historyVisibilityCell.label.text = [VectorL10n roomDetailsHistorySectionMembersOnlySinceJoined];
            
            historyVisibilityCell.enabled = ([visibility isEqualToString:kMXRoomHistoryVisibilityJoined]);
            
            historyVisibilityTickCells[kMXRoomHistoryVisibilityJoined] = historyVisibilityCell;
        }
        
        // Check whether the user can change this option
        historyVisibilityCell.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomHistoryVisibility]);
        historyVisibilityCell.checkBox.alpha = historyVisibilityCell.userInteractionEnabled ? 1.0f : 0.5f;
        
        cell = historyVisibilityCell;
    }
    else if (section == SECTION_TAG_ADDRESSES)
    {
        if (row == ROOM_SETTINGS_ROOM_ADDRESS_NEW_ALIAS)
        {
            MXKTableViewCellWithLabelAndTextField *addAddressCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsNewAddressCellViewIdentifier forIndexPath:indexPath];
            
            // Retrieve the current edited value if any
            NSString *currentValue = (addAddressTextField ? addAddressTextField.text : nil);
            
            addAddressCell.mxkLabelLeadingConstraint.constant = 0;
            addAddressCell.mxkTextFieldLeadingConstraint.constant = tableView.vc_separatorInset.left;
            addAddressCell.mxkTextFieldTrailingConstraint.constant = 15;
            
            addAddressCell.mxkLabel.text = nil;
            
            addAddressCell.accessoryType = UITableViewCellAccessoryNone;
            addAddressCell.accessoryView = [[UIImageView alloc] initWithImage:[AssetImages.plusIcon.image vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]];
            
            addAddressTextField = addAddressCell.mxkTextField;
            addAddressTextField.placeholder = [VectorL10n roomDetailsNewAddressPlaceholder:self.mainSession.matrixRestClient.homeserverSuffix];
            addAddressTextField.attributedPlaceholder = [[NSAttributedString alloc]
                                                         initWithString:addAddressTextField.placeholder
                                                         attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}];
            addAddressTextField.userInteractionEnabled = YES;
            addAddressTextField.text = currentValue;
            addAddressTextField.textColor = ThemeService.shared.theme.textSecondaryColor;
            
            addAddressTextField.tintColor = ThemeService.shared.theme.tintColor;
            addAddressTextField.font = [UIFont systemFontOfSize:17];
            addAddressTextField.borderStyle = UITextBorderStyleNone;
            addAddressTextField.textAlignment = NSTextAlignmentLeft;
            
            addAddressTextField.autocorrectionType = UITextAutocorrectionTypeNo;
            addAddressTextField.spellCheckingType = UITextSpellCheckingTypeNo;
            addAddressTextField.delegate = self;
            
            cell = addAddressCell;
        }
        else if (row == ROOM_SETTINGS_ROOM_ADDRESS_NO_LOCAL_ADDRESS)
        {
            UITableViewCell *addressCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAddressCellViewIdentifier forIndexPath:indexPath];
            
            addressCell.textLabel.font = [UIFont systemFontOfSize:16];
            addressCell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
            addressCell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
            addressCell.accessoryView = nil;
            addressCell.accessoryType = UITableViewCellAccessoryNone;
            addressCell.selectionStyle = UITableViewCellSelectionStyleNone;
            if (mxRoom.isDirect)
            {
                addressCell.textLabel.text = [VectorL10n roomDetailsNoLocalAddressesForDm];
            }
            else
            {
                addressCell.textLabel.text = [VectorL10n roomDetailsNoLocalAddresses];
            }
            
            cell = addressCell;
        }
        else
        {
            UITableViewCell *addressCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAddressCellViewIdentifier forIndexPath:indexPath];
            
            addressCell.textLabel.font = [UIFont systemFontOfSize:16];
            addressCell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
            addressCell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
            addressCell.accessoryView = nil;
            addressCell.accessoryType = UITableViewCellAccessoryNone;
            addressCell.selectionStyle = UITableViewCellSelectionStyleNone;
            
            NSInteger index = row - ROOM_SETTINGS_ROOM_ADDRESS_ALIAS_OFFSET;
            
            if (index < roomAddresses.count)
            {
                NSString *alias = roomAddresses[index];
                NSString *canonicalAlias;
                
                if (updatedItemsDict[kRoomSettingsCanonicalAliasKey])
                {
                    canonicalAlias = updatedItemsDict[kRoomSettingsCanonicalAliasKey];
                }
                else
                {
                    canonicalAlias = mxRoomState.canonicalAlias;
                }
                
                addressCell.textLabel.text = alias;
                
                // Check whether this alias is the main address
                if (canonicalAlias)
                {
                    if ([alias isEqualToString:canonicalAlias])
                    {
                        addressCell.accessoryView = [[UIImageView alloc] initWithImage:AssetImages.mainAliasIcon.image];
                    }
                }
            }
            
            cell = addressCell;
        }
    }
    else if (section == SECTION_TAG_BANNED_USERS)
    {
        UITableViewCell *addressCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAddressCellViewIdentifier forIndexPath:indexPath];
        
        addressCell.textLabel.font = [UIFont systemFontOfSize:16];
        addressCell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
        addressCell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
        addressCell.accessoryView = nil;
        addressCell.accessoryType = UITableViewCellAccessoryNone;
        addressCell.selectionStyle = UITableViewCellSelectionStyleNone;
        
        addressCell.textLabel.text = bannedMembers[row].userId;
        
        cell = addressCell;
    }
    else if (section == SECTION_TAG_BANNED_ADVANCED)
    {
        if (row == ROOM_SETTINGS_ADVANCED_ROOM_ID)
        {
            cell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAdvancedCellViewIdentifier];
            if (!cell)
            {
                cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kRoomSettingsAdvancedCellViewIdentifier];
            }
            
            cell.textLabel.font = [UIFont systemFontOfSize:17];
            if (mxRoom.isDirect)
            {
                cell.textLabel.text = [VectorL10n roomDetailsAdvancedRoomIdForDm];
            }
            else
            {
                cell.textLabel.text = [VectorL10n roomDetailsAdvancedRoomId];
            }
            cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
            
            cell.detailTextLabel.font = [UIFont systemFontOfSize:15];
            cell.detailTextLabel.text = mxRoomState.roomId;
            cell.detailTextLabel.textColor = ThemeService.shared.theme.textSecondaryColor;
            cell.detailTextLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
            
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
        }
        else if (row == ROOM_SETTINGS_ADVANCED_ENCRYPT_TO_VERIFIED)
        {
            MXKTableViewCellWithLabelAndSwitch *roomBlacklistUnverifiedDevicesCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
            
            [roomBlacklistUnverifiedDevicesCell.mxkSwitch addTarget:self action:@selector(toggleBlacklistUnverifiedDevice:) forControlEvents:UIControlEventValueChanged];
            roomBlacklistUnverifiedDevicesCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
            
            roomBlacklistUnverifiedDevicesCell.mxkLabel.text = [VectorL10n roomDetailsAdvancedE2eEncryptionBlacklistUnverifiedDevices];
            
            // For the switch value, use by order:
            // - the MXCrypto.globalBlacklistUnverifiedDevices if its value is YES
            //   In this case, the switch is disabled.
            // - the changed value made by the user
            // - the value used by the crypto
            BOOL blacklistUnverifiedDevices;
            if (mxRoom.mxSession.crypto.globalBlacklistUnverifiedDevices)
            {
                blacklistUnverifiedDevices = YES;
                roomBlacklistUnverifiedDevicesCell.mxkSwitch.enabled = NO;
            }
            else
            {
                roomBlacklistUnverifiedDevicesCell.mxkSwitch.enabled = YES;
                
                if (updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey])
                {
                    blacklistUnverifiedDevices = [((NSNumber*)updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey]) boolValue];
                }
                else
                {
                    blacklistUnverifiedDevices = [mxRoom.mxSession.crypto isBlacklistUnverifiedDevicesInRoom:mxRoom.roomId];
                }
            }
            
            roomBlacklistUnverifiedDevicesCell.mxkSwitch.on = blacklistUnverifiedDevices;
            
            cell = roomBlacklistUnverifiedDevicesCell;
            
            // Force layout before reusing a cell (fix switch displayed outside the screen)
            [cell layoutIfNeeded];
        }
        else if (row == ROOM_SETTINGS_ADVANCED_ENCRYPTION_ENABLED)
        {
            cell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAdvancedE2eEnabledCellViewIdentifier];
            if (!cell)
            {
                cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kRoomSettingsAdvancedE2eEnabledCellViewIdentifier];
            }
            
            cell.textLabel.font = [UIFont systemFontOfSize:17];
            cell.textLabel.numberOfLines = 0;
            if (mxRoom.isDirect)
            {
                cell.textLabel.text = [VectorL10n roomDetailsAdvancedE2eEncryptionEnabledForDm];
            }
            else
            {
                cell.textLabel.text = [VectorL10n roomDetailsAdvancedE2eEncryptionEnabled];
            }
            cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
            
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
        }
        else if (row == ROOM_SETTINGS_ADVANCED_ENABLE_ENCRYPTION)
        {
            MXKTableViewCellWithLabelAndSwitch *roomEncryptionCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
            
            [roomEncryptionCell.mxkSwitch addTarget:self action:@selector(toggleEncryption:) forControlEvents:UIControlEventValueChanged];
            
            roomEncryptionCell.mxkLabel.text = [VectorL10n roomDetailsAdvancedEnableE2eEncryption];
            
            roomEncryptionCell.mxkSwitch.on = (updatedItemsDict[kRoomSettingsEncryptionKey] != nil);
            
            cell = roomEncryptionCell;
        }
        else if (row == ROOM_SETTINGS_ADVANCED_ENCRYPTION_DISABLED)
        {
            cell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAdvancedE2eEnabledCellViewIdentifier];
            if (!cell)
            {
                cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kRoomSettingsAdvancedE2eEnabledCellViewIdentifier];
            }
            
            cell.textLabel.font = [UIFont systemFontOfSize:17];
            cell.textLabel.numberOfLines = 0;
            if (mxRoom.isDirect)
            {
                cell.textLabel.text = [VectorL10n roomDetailsAdvancedE2eEncryptionDisabledForDm];
            }
            else
            {
                cell.textLabel.text = [VectorL10n roomDetailsAdvancedE2eEncryptionDisabled];
            }
            cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
            
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
        }
    }
    
    // Sanity check
    if (!cell)
    {
        MXLogDebug(@"[RoomSettingsViewController] cellForRowAtIndexPath: invalid indexPath");
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
    }
    
    return cell;
}

- (MXKTableViewCellWithLabelAndSwitch*)getLabelAndSwitchCell:(UITableView*)tableView forIndexPath:(NSIndexPath *)indexPath
{
    MXKTableViewCellWithLabelAndSwitch *cell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath];
    
    cell.mxkLabelLeadingConstraint.constant = tableView.vc_separatorInset.left;
    cell.mxkSwitchTrailingConstraint.constant = 15;
    
    cell.mxkLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
    
    cell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
    [cell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventValueChanged];
    
    // Reset the stored `directoryVisibilitySwitch` if the corresponding cell is reused.
    if (cell.mxkSwitch == directoryVisibilitySwitch)
    {
        directoryVisibilitySwitch = nil;
    }
    
    // Force layout before reusing a cell (fix switch displayed outside the screen)
    [cell layoutIfNeeded];
    
    return cell;
}

#pragma mark - UITableViewDelegate

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
{
    cell.backgroundColor = ThemeService.shared.theme.backgroundColor;
    
    // Update the selected background view
    if (ThemeService.shared.theme.selectedBackgroundColor)
    {
        cell.selectedBackgroundView = [[UIView alloc] init];
        cell.selectedBackgroundView.backgroundColor = ThemeService.shared.theme.selectedBackgroundColor;
    }
    else
    {
        if (tableView.style == UITableViewStylePlain)
        {
            cell.selectedBackgroundView = nil;
        }
        else
        {
            cell.selectedBackgroundView.backgroundColor = nil;
        }
    }
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSIndexPath *tagsIndexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
    NSInteger section = tagsIndexPath.section;
    NSInteger row = tagsIndexPath.row;
    
    if (self.tableView == tableView)
    {
        [self dismissFirstResponder];
        
        if (section == SECTION_TAG_MAIN)
        {
            if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO)
            {
                [self onRoomAvatarTap:nil];
            }
            else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC)
            {
                if (topicTextView.editable)
                {
                    [self editRoomTopic];
                }
            }
        }
        else if (section == SECTION_TAG_ACCESS)
        {
            BOOL isUpdated = NO;

            if (row == ROOM_SETTINGS_ROOM_ACCESS_MISSING_ADDRESS_WARNING)
            {
                // Scroll to room addresses section
                NSIndexPath *addressIndexPath = [_tableViewSections exactIndexPathForRowTag:0 sectionTag:SECTION_TAG_ADDRESSES];
                if (addressIndexPath)
                {
                    [tableView scrollToRowAtIndexPath:addressIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
                }
                else
                {
                    addressIndexPath = [_tableViewSections nearestIndexPathForRowTag:0 sectionTag:SECTION_TAG_ADDRESSES];
                    if (addressIndexPath)
                    {
                        [tableView scrollToRowAtIndexPath:addressIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
                    }
                }
            }
            else if (row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ACCESS)
            {
                [self showRoomAccessFlow];
            }
            
            if (isUpdated)
            {
                [self updateSections];
                
                [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
            }
        }
        else if (section == SECTION_TAG_PROMOTION)
        {
            if (row == ROOM_SETTINGS_ROOM_PROMOTE_SECTION_ROW_SUGGEST)
            {
                [self showSuggestToSpaceMembers];
            }
        }
        else if (section == SECTION_TAG_HISTORY)
        {
            // Ignore the selection if the option is already enabled
            TableViewCellWithCheckBoxAndLabel *selectedCell = [self.tableView cellForRowAtIndexPath:indexPath];
            if (! selectedCell.isEnabled)
            {
                MXRoomHistoryVisibility historyVisibility;
                
                if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_ANYONE)
                {
                    historyVisibility = kMXRoomHistoryVisibilityWorldReadable;
                }
                else if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY)
                {
                    historyVisibility = kMXRoomHistoryVisibilityShared;
                }
                else if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_INVITED)
                {
                    historyVisibility = kMXRoomHistoryVisibilityInvited;
                }
                else if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_JOINED)
                {
                    historyVisibility = kMXRoomHistoryVisibilityJoined;
                }
                
                if (historyVisibility)
                {
                    // Prompt the user before taking into account the change
                    [self shouldChangeHistoryVisibility:historyVisibility];
                }
            }
        }
        else if (section == SECTION_TAG_ADDRESSES)
        {
            if (row == ROOM_SETTINGS_ROOM_ADDRESS_NEW_ALIAS)
            {
                NSString *roomAlias = addAddressTextField.text;
                if (!roomAlias.length || [self addRoomAlias:roomAlias])
                {
                    // Reset the input field
                    addAddressTextField.text = nil;
                }
            }
            else if (row >= ROOM_SETTINGS_ROOM_ADDRESS_ALIAS_OFFSET)
            {
                // Prompt user on selected room alias
                UITableViewCell *addressCell = [tableView cellForRowAtIndexPath:indexPath];
                
                dispatch_async(dispatch_get_main_queue(), ^{
                    
                    [self promptUserOnSelectedRoomAlias:addressCell.textLabel];
                    
                });
            }
        }
        else if (section == SECTION_TAG_BANNED_USERS)
        {
            // Show the RoomMemberDetailsViewController on this member so that
            // if the user has enough power level, he will be able to unban him
            RoomMemberDetailsViewController *roomMemberDetailsViewController = [RoomMemberDetailsViewController roomMemberDetailsViewController];
            [roomMemberDetailsViewController displayRoomMember:bannedMembers[row] withMatrixRoom:mxRoom];
            roomMemberDetailsViewController.delegate = self;
            roomMemberDetailsViewController.enableVoipCall = NO;
            
            [self.parentViewController.navigationController pushViewController:roomMemberDetailsViewController animated:NO];
        }
        else if (section == SECTION_TAG_BANNED_ADVANCED && row == ROOM_SETTINGS_ADVANCED_ROOM_ID)
        {
            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
            if (cell)
            {
                // Prompt user to copy the room id (use dispatch_async here to not be stuck by the table refresh).
                dispatch_async(dispatch_get_main_queue(), ^{
                    
                    [self promptUserToCopyRoomId:cell.detailTextLabel];
                    
                });
            }
        }
        
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
    }
}

- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSIndexPath *tagsIndexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
    NSInteger section = tagsIndexPath.section;
    NSInteger row = tagsIndexPath.row;
    
    // Add the swipe to delete only on addresses section
    if (section == SECTION_TAG_ADDRESSES && row >= ROOM_SETTINGS_ROOM_ADDRESS_ALIAS_OFFSET)
    {
        UIContextualAction *removeAddressAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
                                                                                          title:@"    "
                                                                                        handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
            [self removeAddressAtIndexPath:indexPath];
            completionHandler(YES);
        }];
        removeAddressAction.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
        removeAddressAction.image = [AssetImages.removeIcon.image vc_notRenderedImage];
        
        // Create swipe action configuration
        
        NSArray<UIContextualAction*> *actions = @[
            removeAddressAction
        ];
        
        UISwipeActionsConfiguration *swipeActionConfiguration = [UISwipeActionsConfiguration configurationWithActions:actions];
        swipeActionConfiguration.performsFirstActionWithFullSwipe = NO;
        return swipeActionConfiguration;
    }
    
    return nil;
}

#pragma mark -

- (void)shouldChangeHistoryVisibility:(MXRoomHistoryVisibility)historyVisibility
{
    // Prompt the user before applying the change on room history visibility
    [currentAlert dismissViewControllerAnimated:NO completion:nil];
    
    __weak typeof(self) weakSelf = self;
    
    currentAlert = [UIAlertController alertControllerWithTitle:[VectorL10n roomDetailsHistorySectionPromptTitle]
                                                       message:[VectorL10n roomDetailsHistorySectionPromptMsg]
                                                preferredStyle:UIAlertControllerStyleAlert];
    
    [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
                                                     style:UIAlertActionStyleCancel
                                                   handler:^(UIAlertAction * action) {
                                                       
                                                       if (weakSelf)
                                                       {
                                                           typeof(self) self = weakSelf;
                                                           self->currentAlert = nil;
                                                       }
                                                       
                                                   }]];
    
    [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n continue]
                                                     style:UIAlertActionStyleDefault
                                                   handler:^(UIAlertAction * action) {
                                                       
                                                       if (weakSelf)
                                                       {
                                                           typeof(self) self = weakSelf;
                                                           self->currentAlert = nil;
                                                           
                                                           [self changeHistoryVisibility:historyVisibility];
                                                       }
                                                       
                                                   }]];
    
    [currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCChangeHistoryVisibilityAlert"];
    [self presentViewController:currentAlert animated:YES completion:nil];
}

- (void)changeHistoryVisibility:(MXRoomHistoryVisibility)historyVisibility
{
    if (historyVisibility)
    {
        // Disable all history visibility options
        NSArray *tickCells = historyVisibilityTickCells.allValues;
        for (TableViewCellWithCheckBoxAndLabel *historyVisibilityTickCell in tickCells)
        {
            historyVisibilityTickCell.enabled = NO;
        }
        
        // Enable the selected option
        historyVisibilityTickCells[historyVisibility].enabled = YES;
        
        // Check the actual option
        if ([mxRoomState.historyVisibility isEqualToString:historyVisibility])
        {
            // No change on history visibility
            [updatedItemsDict removeObjectForKey:kRoomSettingsHistoryVisibilityKey];
        }
        else
        {
            updatedItemsDict[kRoomSettingsHistoryVisibilityKey] = historyVisibility;
        }
        
        [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
    }
}

- (BOOL)canSetCanonicalAlias
{
    BOOL canSetCanonicalAlias = NO;
    if (self.mainSession)
    {
        // Check user's power level to know whether the user is allowed to set the main address
        MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
        NSInteger oneSelfPowerLevel = [mxRoomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId];

        if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomAliases])
        {
            canSetCanonicalAlias = YES;
        }
    }

    return canSetCanonicalAlias;
}

- (void)shouldRemoveCanonicalAlias:(void (^)(void))didRemoveCanonicalAlias
{
    // Prompt the user before removing the current main address
    [currentAlert dismissViewControllerAnimated:NO completion:nil];
    
    __weak typeof(self) weakSelf = self;
    
    currentAlert = [UIAlertController alertControllerWithTitle:[VectorL10n roomDetailsAddressesDisableMainAddressPromptTitle]
                                                       message:[VectorL10n roomDetailsAddressesDisableMainAddressPromptMsg]
                                                preferredStyle:UIAlertControllerStyleAlert];
    
    [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
                                                     style:UIAlertActionStyleCancel
                                                   handler:^(UIAlertAction * action) {
                                                       
                                                       if (weakSelf)
                                                       {
                                                           typeof(self) self = weakSelf;
                                                           self->currentAlert = nil;
                                                       }
                                                       
                                                   }]];
    
    [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n continue]
                                                     style:UIAlertActionStyleDefault
                                                   handler:^(UIAlertAction * action) {
                                                       
                                                       if (weakSelf)
                                                       {
                                                           typeof(self) self = weakSelf;
                                                           self->currentAlert = nil;
                                                           
                                                           // Remove the canonical address
                                                           if (self->mxRoomState.canonicalAlias.length)
                                                           {
                                                               self->updatedItemsDict[kRoomSettingsCanonicalAliasKey] = @"";
                                                           }
                                                           else
                                                           {
                                                               [self->updatedItemsDict removeObjectForKey:kRoomSettingsCanonicalAliasKey];
                                                           }
                                                           
                                                           [self updateSections];
                                                           
                                                           [self getNavigationItem].rightBarButtonItem.enabled = (self->updatedItemsDict.count != 0);
                                                           
                                                           if (didRemoveCanonicalAlias)
                                                           {
                                                               didRemoveCanonicalAlias();
                                                           }
                                                       }
                                                       
                                                   }]];
    
    [currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCRemoveCanonicalAliasAlert"];
    [self presentViewController:currentAlert animated:YES completion:nil];
}

#pragma mark - MXKRoomMemberDetailsViewControllerDelegate

- (void)roomMemberDetailsViewController:(MXKRoomMemberDetailsViewController *)roomMemberDetailsViewController startChatWithMemberId:(NSString *)matrixId completion:(void (^)(void))completion
{
    [[AppDelegate theDelegate] showNewDirectChat:matrixId withMatrixSession:mxRoom.mxSession completion:completion];
}

#pragma mark - actions

- (void)onRoomAvatarTap:(UITapGestureRecognizer *)recognizer
{
    SingleImagePickerPresenter *singleImagePickerPresenter = [[SingleImagePickerPresenter alloc] initWithSession:self.mainSession];
    singleImagePickerPresenter.delegate = self;
    
    UIView *sourceView;
    
    NSIndexPath *indexPath = [_tableViewSections exactIndexPathForRowTag:ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO sectionTag:SECTION_TAG_MAIN];
    if (indexPath)
    {
        sourceView = [self.tableView cellForRowAtIndexPath:indexPath];
    }
    
    [singleImagePickerPresenter presentFrom:self sourceView:sourceView sourceRect:sourceView.bounds animated:YES];
    
    self.imagePickerPresenter = singleImagePickerPresenter;
}

- (void)toggleRoomNotification:(UISwitch*)theSwitch
{
    if (theSwitch.on == (mxRoom.isMute || mxRoom.isMentionsOnly))
    {
        [updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey];
    }
    else
    {
        updatedItemsDict[kRoomSettingsMuteNotifKey] = @(theSwitch.on);
    }
    
    [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}

- (void)toggleFavorite:(UISwitch *)theSwitch
{
    if (theSwitch.on)
    {
        if (mxRoom.accountData.tags[kMXRoomTagFavourite])
        {
            [updatedItemsDict removeObjectForKey:kRoomSettingsTagKey];
        }
        else
        {
            updatedItemsDict[kRoomSettingsTagKey] = kMXRoomTagFavourite;
        }
    }
    else
    {
        // The user wants to unselect this tag
        // Retrieve the current change on room tag (if any)
        NSString *updatedRoomTag = updatedItemsDict[kRoomSettingsTagKey];
        
        // Check the actual tag on mxRoom
        if (mxRoom.accountData.tags[kMXRoomTagFavourite])
        {
            // The actual tag must be updated, check whether another tag is already set
            if (!updatedRoomTag)
            {
                updatedItemsDict[kRoomSettingsTagKey] = @"";
            }
        }
        else if (updatedRoomTag && [updatedRoomTag isEqualToString:kMXRoomTagFavourite])
        {
            // Cancel the updated tag, but take into account the cancellation of another tag when 'tappedRoomTag' was selected.
            if (mxRoom.accountData.tags.count)
            {
                updatedItemsDict[kRoomSettingsTagKey] = @"";
            }
            else
            {
                [updatedItemsDict removeObjectForKey:kRoomSettingsTagKey];
            }
        }
    }
    
    [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}

- (void)toggleDirectChat:(UISwitch*)theSwitch
{
    if (theSwitch.on == mxRoom.isDirect)
    {
        [updatedItemsDict removeObjectForKey:kRoomSettingsDirectChatKey];
    }
    else
    {
        updatedItemsDict[kRoomSettingsDirectChatKey] = @(theSwitch.on);
    }
    
    [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}

- (void)toggleEncryption:(UISwitch*)theSwitch
{
    if (theSwitch.on)
    {
        updatedItemsDict[kRoomSettingsEncryptionKey] = @(YES);

        [self getNavigationItem].rightBarButtonItem.enabled = self->updatedItemsDict.count;
    }
    else
    {
        [updatedItemsDict removeObjectForKey:kRoomSettingsEncryptionKey];
    }
    
    [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}

- (void)toggleBlacklistUnverifiedDevice:(UISwitch*)theSwitch
{
    if ([mxRoom.mxSession.crypto isBlacklistUnverifiedDevicesInRoom:mxRoom.roomId] != theSwitch.on)
    {
        updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey] = @(theSwitch.on);
    }
    else
    {
        [updatedItemsDict removeObjectForKey:kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey];
    }
    
    [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}


- (void)toggleDirectoryVisibility:(UISwitch*)theSwitch
{
    MXRoomDirectoryVisibility visibility = theSwitch.on ? kMXRoomDirectoryVisibilityPublic : kMXRoomDirectoryVisibilityPrivate;
    
    // Check whether the actual settings has been retrieved
    if (actualDirectoryVisibility)
    {
        if ([visibility isEqualToString:actualDirectoryVisibility])
        {
            [updatedItemsDict removeObjectForKey:kRoomSettingsDirectoryKey];
        }
        else
        {
            updatedItemsDict[kRoomSettingsDirectoryKey] = visibility;
        }
    }
    else
    {
        updatedItemsDict[kRoomSettingsDirectoryKey] = visibility;
    }
    
    [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}

- (void)showRoomAccessFlow
{
    MXRoom *room = [self.mainSession roomWithRoomId:self.roomId];

    if (room) {
        roomAccessPresenter = [[RoomAccessCoordinatorBridgePresenter alloc] initWithRoom:room parentSpaceId:self.parentSpaceId];
        roomAccessPresenter.delegate = self;
        [roomAccessPresenter presentFrom:self animated:YES];
    }
}

- (void)showSuggestToSpaceMembers
{
    MXRoom *room = [self.mainSession roomWithRoomId:self.roomId];

    if (room) {
        roomSuggestionPresenter = [[RoomSuggestionCoordinatorBridgePresenter alloc] initWithRoom:room];
        roomSuggestionPresenter.delegate = self;
        [roomSuggestionPresenter presentFrom:self animated:YES];
    }
}

- (void)setRoomAliasAsMainAddress:(NSString *)alias
{
    NSString *currentCanonicalAlias = mxRoomState.canonicalAlias;
    
    // Update the current canonical address
    if ([alias isEqualToString:currentCanonicalAlias])
    {
        [updatedItemsDict removeObjectForKey:kRoomSettingsCanonicalAliasKey];
    }
    else
    {
        updatedItemsDict[kRoomSettingsCanonicalAliasKey] = alias;
    }
    
    [self updateSections];
    
    [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}

- (void)removeAddressAtIndexPath:(NSIndexPath *)indexPath
{
    indexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
    NSInteger row = indexPath.row;
    
    row = ROOM_SETTINGS_ROOM_ADDRESS_ALIAS_OFFSET - row;
    
    if (row < roomAddresses.count)
    {
        NSString *alias = roomAddresses[row];
        [self removeRoomAlias:alias];
    }
}

- (void)removeRoomAlias:(NSString*)roomAlias
{
    NSString *canonicalAlias;
    
    if (updatedItemsDict[kRoomSettingsCanonicalAliasKey])
    {
        canonicalAlias = updatedItemsDict[kRoomSettingsCanonicalAliasKey];
    }
    else
    {
        canonicalAlias = mxRoomState.canonicalAlias;
    }
    
    // Check whether this alias is the main address
    if (canonicalAlias && [roomAlias isEqualToString:canonicalAlias])
    {
        // Prompt user before remove this alias which is the main address
        [self shouldRemoveCanonicalAlias:^{
            
            // The room alias can be removed now
            [self removeRoomAlias:roomAlias];
            
        }];
    }
    else
    {
        // Check whether the alias has just been added
        NSMutableArray<NSString *> *addedAlias = updatedItemsDict[kRoomSettingsNewAliasesKey];
        if (addedAlias && [addedAlias indexOfObject:roomAlias] != NSNotFound)
        {
            [addedAlias removeObject:roomAlias];
            
            if (!addedAlias.count)
            {
                [updatedItemsDict removeObjectForKey:kRoomSettingsNewAliasesKey];
            }
        }
        else
        {
            NSMutableArray<NSString *> *removedAlias = updatedItemsDict[kRoomSettingsRemovedAliasesKey];
            if (!removedAlias)
            {
                removedAlias = [NSMutableArray array];
                updatedItemsDict[kRoomSettingsRemovedAliasesKey] = removedAlias;
            }
            
            [removedAlias addObject:roomAlias];
        }
        
        [self updateSections];
        
        [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
    }
}

- (BOOL)addRoomAlias:(NSString*)roomAlias
{
    // Check whether the provided alias is valid
    if ([MXTools isMatrixRoomAlias:roomAlias])
    {
        // Check whether this alias has just been deleted
        NSMutableArray<NSString *> *removedAlias = updatedItemsDict[kRoomSettingsRemovedAliasesKey];
        if (removedAlias && [removedAlias indexOfObject:roomAlias] != NSNotFound)
        {
            [removedAlias removeObject:roomAlias];
            
            if (!removedAlias.count)
            {
                [updatedItemsDict removeObjectForKey:kRoomSettingsRemovedAliasesKey];
            }
        }
        // Check whether this alias is not already defined for this room
        else if ([roomAddresses indexOfObject:roomAlias] == NSNotFound)
        {
            NSMutableArray<NSString *> *addedAlias = updatedItemsDict[kRoomSettingsNewAliasesKey];
            if (!addedAlias)
            {
                addedAlias = [NSMutableArray array];
                updatedItemsDict[kRoomSettingsNewAliasesKey] = addedAlias;
            }
            
            [addedAlias addObject:roomAlias];
        }
        
        if (!roomAddresses.count)
        {
            // The first added alias is defined as the main address by default.
            // Update the current canonical address.
            NSString *currentCanonicalAlias = mxRoomState.canonicalAlias;
            if (currentCanonicalAlias && [roomAlias isEqualToString:currentCanonicalAlias])
            {
                // The right canonical alias is already defined
                [updatedItemsDict removeObjectForKey:kRoomSettingsCanonicalAliasKey];
            }
            else
            {
                updatedItemsDict[kRoomSettingsCanonicalAliasKey] = roomAlias;
            }
        }
        
        [self updateSections];
        
        [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
        
        return YES;
    }
    
    // Prompt here user for invalid alias
    __weak typeof(self) weakSelf = self;
    
    [currentAlert dismissViewControllerAnimated:NO completion:nil];
    
    NSString *alertMsg = [VectorL10n roomDetailsAddressesInvalidAddressPromptMsg:roomAlias];
    
    currentAlert = [UIAlertController alertControllerWithTitle:[VectorL10n roomDetailsAddressesInvalidAddressPromptTitle]
                                                       message:alertMsg
                                                preferredStyle:UIAlertControllerStyleAlert];
    
    [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n ok]
                                                     style:UIAlertActionStyleDefault
                                                   handler:^(UIAlertAction * action) {
                                                       
                                                       if (weakSelf)
                                                       {
                                                           typeof(self) self = weakSelf;
                                                           self->currentAlert = nil;
                                                       }
                                                       
                                                   }]];
    
    [currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCAddAliasAlert"];
    [self presentViewController:currentAlert animated:YES completion:nil];
    
    return NO;
}

#pragma mark - TableViewCellWithCheckBoxesDelegate

- (void)tableViewCellWithCheckBoxes:(TableViewCellWithCheckBoxes *)tableViewCellWithCheckBoxes didTapOnCheckBoxAtIndex:(NSUInteger)index
{
    if (tableViewCellWithCheckBoxes == roomTagCell)
    {
        NSString *tappedRoomTag = (index == 0) ? kMXRoomTagFavourite : kMXRoomTagLowPriority;
        BOOL isCurrentlySelected = [roomTagCell checkBoxValueAtIndex:index];
        
        if (isCurrentlySelected)
        {
            // The user wants to unselect this tag
            // Retrieve the current change on room tag (if any)
            NSString *updatedRoomTag = updatedItemsDict[kRoomSettingsTagKey];
            
            // Check the actual tag on mxRoom
            if (mxRoom.accountData.tags[tappedRoomTag])
            {
                // The actual tag must be updated, check whether another tag is already set
                if (!updatedRoomTag)
                {
                    updatedItemsDict[kRoomSettingsTagKey] = @"";
                }
            }
            else if (updatedRoomTag && [updatedRoomTag isEqualToString:tappedRoomTag])
            {
                // Cancel the updated tag, but take into account the cancellation of another tag when 'tappedRoomTag' was selected.
                if (mxRoom.accountData.tags.count)
                {
                    updatedItemsDict[kRoomSettingsTagKey] = @"";
                }
                else
                {
                    [updatedItemsDict removeObjectForKey:kRoomSettingsTagKey];
                }
            }
            
            // Unselect the tag
            [roomTagCell setCheckBoxValue:NO atIndex:index];
        }
        else
        {
            // The user wants to select this room tag
            // Check the actual tag on mxRoom
            if (mxRoom.accountData.tags[tappedRoomTag])
            {
                [updatedItemsDict removeObjectForKey:kRoomSettingsTagKey];
            }
            else
            {
                updatedItemsDict[kRoomSettingsTagKey] = tappedRoomTag;
            }
            
            // Select the tapped tag
            [roomTagCell setCheckBoxValue:YES atIndex:index];
        }
        
        [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
    }
}

#pragma mark - SingleImagePickerPresenterDelegate

- (void)singleImagePickerPresenterDidCancel:(SingleImagePickerPresenter *)presenter
{
    [presenter dismissWithAnimated:YES completion:nil];
    self.imagePickerPresenter = nil;
}

- (void)singleImagePickerPresenter:(SingleImagePickerPresenter *)presenter didSelectImageData:(NSData *)imageData withUTI:(MXKUTI *)uti
{
    [presenter dismissWithAnimated:YES completion:nil];
    self.imagePickerPresenter = nil;
    
    UIImage *image = [UIImage imageWithData:imageData];
    if (image)
    {
        [self getNavigationItem].rightBarButtonItem.enabled = YES;
        
        updatedItemsDict[kRoomSettingsAvatarKey] = image;
        
        [self refreshRoomSettings];
    }
}

#pragma mark - TableViewSectionsDelegate

- (void)tableViewSectionsDidUpdateSections:(TableViewSections *)sections
{
    [self.tableView reloadData];
}

#pragma mark - RoomAccessCoordinatorBridgePresenterDelegate

- (void)roomAccessCoordinatorBridgePresenterDelegate:(RoomAccessCoordinatorBridgePresenter *)coordinatorBridgePresenter didCancelRoomWithId:(NSString *)roomId
{
    if (![roomId isEqualToString: self.roomId]) {
        // Room Access Coordinator upgraded the actual room -> Need to move to replacement room
        [self.delegate roomSettingsViewController:self didReplaceRoomWithReplacementId:roomId];
    }

    MXWeakify(self);
    [roomAccessPresenter dismissWithAnimated:YES completion:^{
        MXStrongifyAndReturnIfNil(self);
        self->roomAccessPresenter = nil;
    }];
}

- (void)roomAccessCoordinatorBridgePresenterDelegate:(RoomAccessCoordinatorBridgePresenter *)coordinatorBridgePresenter didCompleteRoomWithId:(NSString *)roomId
{
    if (![roomId isEqualToString: self.roomId]) {
        // Room Access Coordinator upgraded the actual room -> Need to move to replacement room
        [self.delegate roomSettingsViewController:self didReplaceRoomWithReplacementId:roomId];
    }

    MXWeakify(self);
    [roomAccessPresenter dismissWithAnimated:YES completion:^{
        MXStrongifyAndReturnIfNil(self);
        self->roomAccessPresenter = nil;
    }];
}

#pragma mark - RoomSuggestionCoordinatorBridgePresenterDelegate

- (void)roomSuggestionCoordinatorBridgePresenterDelegateDidCancel:(RoomSuggestionCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
    [roomSuggestionPresenter dismissWithAnimated:YES completion:nil];
    roomSuggestionPresenter = nil;
}

- (void)roomSuggestionCoordinatorBridgePresenterDelegateDidComplete:(RoomSuggestionCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
    MXWeakify(self);
    [roomSuggestionPresenter dismissWithAnimated:YES completion:^{
        MXStrongifyAndReturnIfNil(self);
        self->roomSuggestionPresenter = nil;
        [self refreshRoomSettings];
    }];
}

@end
